aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorJoerg Albert <jal2@gmx.de>2009-09-05 10:07:47 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-09-08 16:31:10 -0400
commitfea6734a0e444c31c99a1271154bb0281d7908d8 (patch)
treeaa6af0ecb5ddafd7ac35e3f70e11d11c83edcd83 /drivers/net
parent7f42c37aa676825fea329a7bec2fefe51033b3e9 (diff)
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 <jal2@gmx.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/ath/ar9170/phy.c165
1 files changed, 164 insertions, 1 deletions
diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c
index 108ebfe21fcf..b3e5cf3735b0 100644
--- a/drivers/net/wireless/ath/ar9170/phy.c
+++ b/drivers/net/wireless/ath/ar9170/phy.c
@@ -556,7 +556,6 @@ int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band)
556 if (err) 556 if (err)
557 return err; 557 return err;
558 558
559 /* TODO: (heavy clip) regulatory domain power level fine-tuning. */
560 err = ar9170_init_phy_from_eeprom(ar, is_2ghz, is_40mhz); 559 err = ar9170_init_phy_from_eeprom(ar, is_2ghz, is_40mhz);
561 if (err) 560 if (err)
562 return err; 561 return err;
@@ -1238,6 +1237,164 @@ static int ar9170_set_freq_cal_data(struct ar9170 *ar,
1238 return ar9170_regwrite_result(); 1237 return ar9170_regwrite_result();
1239} 1238}
1240 1239
1240static u8 ar9170_get_max_edge_power(struct ar9170 *ar,
1241 struct ar9170_calctl_edges edges[],
1242 u32 freq)
1243{
1244/* TODO: move somewhere else */
1245#define AR5416_MAX_RATE_POWER 63
1246
1247 int i;
1248 u8 rc = AR5416_MAX_RATE_POWER;
1249 u8 f;
1250 if (freq < 3000)
1251 f = freq - 2300;
1252 else
1253 f = (freq - 4800) / 5;
1254
1255 for (i = 0; i < AR5416_NUM_BAND_EDGES; i++) {
1256 if (edges[i].channel == 0xff)
1257 break;
1258 if (f == edges[i].channel) {
1259 /* exact freq match */
1260 rc = edges[i].power_flags & ~AR9170_CALCTL_EDGE_FLAGS;
1261 break;
1262 }
1263 if (i > 0 && f < edges[i].channel) {
1264 if (f > edges[i-1].channel &&
1265 edges[i-1].power_flags & AR9170_CALCTL_EDGE_FLAGS) {
1266 /* lower channel has the inband flag set */
1267 rc = edges[i-1].power_flags &
1268 ~AR9170_CALCTL_EDGE_FLAGS;
1269 }
1270 break;
1271 }
1272 }
1273
1274 if (i == AR5416_NUM_BAND_EDGES) {
1275 if (f > edges[i-1].channel &&
1276 edges[i-1].power_flags & AR9170_CALCTL_EDGE_FLAGS) {
1277 /* lower channel has the inband flag set */
1278 rc = edges[i-1].power_flags &
1279 ~AR9170_CALCTL_EDGE_FLAGS;
1280 }
1281 }
1282 return rc;
1283}
1284
1285/* calculate the conformance test limits and apply them to ar->power*
1286 * (derived from otus hal/hpmain.c, line 3706 ff.)
1287 */
1288static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
1289{
1290 u8 ctl_grp; /* CTL group */
1291 u8 ctl_idx; /* CTL index */
1292 int i, j;
1293 struct ctl_modes {
1294 u8 ctl_mode;
1295 u8 max_power;
1296 u8 *pwr_cal_data;
1297 int pwr_cal_len;
1298 } *modes;
1299
1300 /* order is relevant in the mode_list_*: we fall back to the
1301 * lower indices if any mode is missed in the EEPROM.
1302 */
1303 struct ctl_modes mode_list_2ghz[] = {
1304 { CTL_11B, 0, ar->power_2G_cck, 4 },
1305 { CTL_11G, 0, ar->power_2G_ofdm, 4 },
1306 { CTL_2GHT20, 0, ar->power_2G_ht20, 8 },
1307 { CTL_2GHT40, 0, ar->power_2G_ht40, 8 },
1308 };
1309 struct ctl_modes mode_list_5ghz[] = {
1310 { CTL_11A, 0, ar->power_5G_leg, 4 },
1311 { CTL_5GHT20, 0, ar->power_5G_ht20, 8 },
1312 { CTL_5GHT40, 0, ar->power_5G_ht40, 8 },
1313 };
1314 int nr_modes;
1315
1316#define EDGES(c, n) (ar->eeprom.ctl_data[c].control_edges[n])
1317
1318 /* TODO: investigate the differences between OTUS'
1319 * hpreg.c::zfHpGetRegulatoryDomain() and
1320 * ath/regd.c::ath_regd_get_band_ctl() -
1321 * e.g. for FCC3_WORLD the OTUS procedure
1322 * always returns CTL_FCC, while the one in ath/ delivers
1323 * CTL_ETSI for 2GHz and CTL_FCC for 5GHz.
1324 */
1325 ctl_grp = ath_regd_get_band_ctl(&ar->common.regulatory,
1326 ar->hw->conf.channel->band);
1327
1328 /* ctl group not found - either invalid band (NO_CTL) or ww roaming */
1329 if (ctl_grp == NO_CTL || ctl_grp == SD_NO_CTL)
1330 ctl_grp = CTL_FCC;
1331
1332 if (ctl_grp != CTL_FCC)
1333 /* skip CTL and heavy clip for CTL_MKK and CTL_ETSI */
1334 return;
1335
1336 if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) {
1337 modes = mode_list_2ghz;
1338 nr_modes = ARRAY_SIZE(mode_list_2ghz);
1339 } else {
1340 modes = mode_list_5ghz;
1341 nr_modes = ARRAY_SIZE(mode_list_5ghz);
1342 }
1343
1344 for (i = 0; i < nr_modes; i++) {
1345 u8 c = ctl_grp | modes[i].ctl_mode;
1346 for (ctl_idx = 0; ctl_idx < AR5416_NUM_CTLS; ctl_idx++)
1347 if (c == ar->eeprom.ctl_index[ctl_idx])
1348 break;
1349 if (ctl_idx < AR5416_NUM_CTLS) {
1350 int f_off = 0;
1351
1352 /* adjust freq for 40MHz */
1353 if (modes[i].ctl_mode == CTL_2GHT40 ||
1354 modes[i].ctl_mode == CTL_5GHT40) {
1355 if (bw == AR9170_BW_40_BELOW)
1356 f_off = -10;
1357 else
1358 f_off = 10;
1359 }
1360
1361 modes[i].max_power =
1362 ar9170_get_max_edge_power(ar, EDGES(ctl_idx, 1),
1363 freq+f_off);
1364
1365 /* TODO: check if the regulatory max. power is
1366 * controlled by cfg80211 for DFS
1367 * (hpmain applies it to max_power itself for DFS freq)
1368 */
1369
1370 } else {
1371 /* Workaround in otus driver, hpmain.c, line 3906:
1372 * if no data for 5GHT20 are found, take the
1373 * legacy 5G value.
1374 * We extend this here to fallback from any other *HT or
1375 * 11G, too.
1376 */
1377 int k = i;
1378
1379 modes[i].max_power = AR5416_MAX_RATE_POWER;
1380 while (k-- > 0) {
1381 if (modes[k].max_power !=
1382 AR5416_MAX_RATE_POWER) {
1383 modes[i].max_power = modes[k].max_power;
1384 break;
1385 }
1386 }
1387 }
1388
1389 /* apply max power to pwr_cal_data (ar->power_*) */
1390 for (j = 0; j < modes[i].pwr_cal_len; j++) {
1391 modes[i].pwr_cal_data[j] = min(modes[i].pwr_cal_data[j],
1392 modes[i].max_power);
1393 }
1394 }
1395#undef EDGES
1396}
1397
1241static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) 1398static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
1242{ 1399{
1243 struct ar9170_calibration_target_power_legacy *ctpl; 1400 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)
1340 ctph[idx + 1].power[n]); 1497 ctph[idx + 1].power[n]);
1341 } 1498 }
1342 1499
1500
1501 /* calc. conformance test limits and apply to ar->power*[] */
1502 ar9170_calc_ctl(ar, freq, bw);
1503
1504 /* TODO: (heavy clip) regulatory domain power level fine-tuning. */
1505
1343 /* set ACK/CTS TX power */ 1506 /* set ACK/CTS TX power */
1344 ar9170_regwrite_begin(ar); 1507 ar9170_regwrite_begin(ar);
1345 1508