diff options
Diffstat (limited to 'drivers/net/wireless/ath/ar9170/phy.c')
-rw-r--r-- | drivers/net/wireless/ath/ar9170/phy.c | 99 |
1 files changed, 82 insertions, 17 deletions
diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c index dbd488da18b1..45a415ea809a 100644 --- a/drivers/net/wireless/ath/ar9170/phy.c +++ b/drivers/net/wireless/ath/ar9170/phy.c | |||
@@ -1239,9 +1239,6 @@ static u8 ar9170_get_max_edge_power(struct ar9170 *ar, | |||
1239 | struct ar9170_calctl_edges edges[], | 1239 | struct ar9170_calctl_edges edges[], |
1240 | u32 freq) | 1240 | u32 freq) |
1241 | { | 1241 | { |
1242 | /* TODO: move somewhere else */ | ||
1243 | #define AR5416_MAX_RATE_POWER 63 | ||
1244 | |||
1245 | int i; | 1242 | int i; |
1246 | u8 rc = AR5416_MAX_RATE_POWER; | 1243 | u8 rc = AR5416_MAX_RATE_POWER; |
1247 | u8 f; | 1244 | u8 f; |
@@ -1259,10 +1256,11 @@ static u8 ar9170_get_max_edge_power(struct ar9170 *ar, | |||
1259 | break; | 1256 | break; |
1260 | } | 1257 | } |
1261 | if (i > 0 && f < edges[i].channel) { | 1258 | if (i > 0 && f < edges[i].channel) { |
1262 | if (f > edges[i-1].channel && | 1259 | if (f > edges[i - 1].channel && |
1263 | edges[i-1].power_flags & AR9170_CALCTL_EDGE_FLAGS) { | 1260 | edges[i - 1].power_flags & |
1261 | AR9170_CALCTL_EDGE_FLAGS) { | ||
1264 | /* lower channel has the inband flag set */ | 1262 | /* lower channel has the inband flag set */ |
1265 | rc = edges[i-1].power_flags & | 1263 | rc = edges[i - 1].power_flags & |
1266 | ~AR9170_CALCTL_EDGE_FLAGS; | 1264 | ~AR9170_CALCTL_EDGE_FLAGS; |
1267 | } | 1265 | } |
1268 | break; | 1266 | break; |
@@ -1270,18 +1268,48 @@ static u8 ar9170_get_max_edge_power(struct ar9170 *ar, | |||
1270 | } | 1268 | } |
1271 | 1269 | ||
1272 | if (i == AR5416_NUM_BAND_EDGES) { | 1270 | if (i == AR5416_NUM_BAND_EDGES) { |
1273 | if (f > edges[i-1].channel && | 1271 | if (f > edges[i - 1].channel && |
1274 | edges[i-1].power_flags & AR9170_CALCTL_EDGE_FLAGS) { | 1272 | edges[i - 1].power_flags & AR9170_CALCTL_EDGE_FLAGS) { |
1275 | /* lower channel has the inband flag set */ | 1273 | /* lower channel has the inband flag set */ |
1276 | rc = edges[i-1].power_flags & | 1274 | rc = edges[i - 1].power_flags & |
1277 | ~AR9170_CALCTL_EDGE_FLAGS; | 1275 | ~AR9170_CALCTL_EDGE_FLAGS; |
1278 | } | 1276 | } |
1279 | } | 1277 | } |
1280 | return rc; | 1278 | return rc; |
1281 | } | 1279 | } |
1282 | 1280 | ||
1283 | /* calculate the conformance test limits and apply them to ar->power* | 1281 | static u8 ar9170_get_heavy_clip(struct ar9170 *ar, |
1284 | * (derived from otus hal/hpmain.c, line 3706 ff.) | 1282 | struct ar9170_calctl_edges edges[], |
1283 | u32 freq, enum ar9170_bw bw) | ||
1284 | { | ||
1285 | u8 f; | ||
1286 | int i; | ||
1287 | u8 rc = 0; | ||
1288 | |||
1289 | if (freq < 3000) | ||
1290 | f = freq - 2300; | ||
1291 | else | ||
1292 | f = (freq - 4800) / 5; | ||
1293 | |||
1294 | if (bw == AR9170_BW_40_BELOW || bw == AR9170_BW_40_ABOVE) | ||
1295 | rc |= 0xf0; | ||
1296 | |||
1297 | for (i = 0; i < AR5416_NUM_BAND_EDGES; i++) { | ||
1298 | if (edges[i].channel == 0xff) | ||
1299 | break; | ||
1300 | if (f == edges[i].channel) { | ||
1301 | if (!(edges[i].power_flags & AR9170_CALCTL_EDGE_FLAGS)) | ||
1302 | rc |= 0x0f; | ||
1303 | break; | ||
1304 | } | ||
1305 | } | ||
1306 | |||
1307 | return rc; | ||
1308 | } | ||
1309 | |||
1310 | /* | ||
1311 | * calculate the conformance test limits and the heavy clip parameter | ||
1312 | * and apply them to ar->power* (derived from otus hal/hpmain.c, line 3706) | ||
1285 | */ | 1313 | */ |
1286 | static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) | 1314 | static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) |
1287 | { | 1315 | { |
@@ -1295,7 +1323,8 @@ static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) | |||
1295 | int pwr_cal_len; | 1323 | int pwr_cal_len; |
1296 | } *modes; | 1324 | } *modes; |
1297 | 1325 | ||
1298 | /* order is relevant in the mode_list_*: we fall back to the | 1326 | /* |
1327 | * order is relevant in the mode_list_*: we fall back to the | ||
1299 | * lower indices if any mode is missed in the EEPROM. | 1328 | * lower indices if any mode is missed in the EEPROM. |
1300 | */ | 1329 | */ |
1301 | struct ctl_modes mode_list_2ghz[] = { | 1330 | struct ctl_modes mode_list_2ghz[] = { |
@@ -1313,7 +1342,10 @@ static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) | |||
1313 | 1342 | ||
1314 | #define EDGES(c, n) (ar->eeprom.ctl_data[c].control_edges[n]) | 1343 | #define EDGES(c, n) (ar->eeprom.ctl_data[c].control_edges[n]) |
1315 | 1344 | ||
1316 | /* TODO: investigate the differences between OTUS' | 1345 | ar->phy_heavy_clip = 0; |
1346 | |||
1347 | /* | ||
1348 | * TODO: investigate the differences between OTUS' | ||
1317 | * hpreg.c::zfHpGetRegulatoryDomain() and | 1349 | * hpreg.c::zfHpGetRegulatoryDomain() and |
1318 | * ath/regd.c::ath_regd_get_band_ctl() - | 1350 | * ath/regd.c::ath_regd_get_band_ctl() - |
1319 | * e.g. for FCC3_WORLD the OTUS procedure | 1351 | * e.g. for FCC3_WORLD the OTUS procedure |
@@ -1347,6 +1379,15 @@ static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) | |||
1347 | if (ctl_idx < AR5416_NUM_CTLS) { | 1379 | if (ctl_idx < AR5416_NUM_CTLS) { |
1348 | int f_off = 0; | 1380 | int f_off = 0; |
1349 | 1381 | ||
1382 | /* determine heav clip parameter from | ||
1383 | the 11G edges array */ | ||
1384 | if (modes[i].ctl_mode == CTL_11G) { | ||
1385 | ar->phy_heavy_clip = | ||
1386 | ar9170_get_heavy_clip(ar, | ||
1387 | EDGES(ctl_idx, 1), | ||
1388 | freq, bw); | ||
1389 | } | ||
1390 | |||
1350 | /* adjust freq for 40MHz */ | 1391 | /* adjust freq for 40MHz */ |
1351 | if (modes[i].ctl_mode == CTL_2GHT40 || | 1392 | if (modes[i].ctl_mode == CTL_2GHT40 || |
1352 | modes[i].ctl_mode == CTL_5GHT40) { | 1393 | modes[i].ctl_mode == CTL_5GHT40) { |
@@ -1360,13 +1401,15 @@ static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) | |||
1360 | ar9170_get_max_edge_power(ar, EDGES(ctl_idx, 1), | 1401 | ar9170_get_max_edge_power(ar, EDGES(ctl_idx, 1), |
1361 | freq+f_off); | 1402 | freq+f_off); |
1362 | 1403 | ||
1363 | /* TODO: check if the regulatory max. power is | 1404 | /* |
1405 | * TODO: check if the regulatory max. power is | ||
1364 | * controlled by cfg80211 for DFS | 1406 | * controlled by cfg80211 for DFS |
1365 | * (hpmain applies it to max_power itself for DFS freq) | 1407 | * (hpmain applies it to max_power itself for DFS freq) |
1366 | */ | 1408 | */ |
1367 | 1409 | ||
1368 | } else { | 1410 | } else { |
1369 | /* Workaround in otus driver, hpmain.c, line 3906: | 1411 | /* |
1412 | * Workaround in otus driver, hpmain.c, line 3906: | ||
1370 | * if no data for 5GHT20 are found, take the | 1413 | * if no data for 5GHT20 are found, take the |
1371 | * legacy 5G value. | 1414 | * legacy 5G value. |
1372 | * We extend this here to fallback from any other *HT or | 1415 | * We extend this here to fallback from any other *HT or |
@@ -1390,6 +1433,19 @@ static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) | |||
1390 | modes[i].max_power); | 1433 | modes[i].max_power); |
1391 | } | 1434 | } |
1392 | } | 1435 | } |
1436 | |||
1437 | if (ar->phy_heavy_clip & 0xf0) { | ||
1438 | ar->power_2G_ht40[0]--; | ||
1439 | ar->power_2G_ht40[1]--; | ||
1440 | ar->power_2G_ht40[2]--; | ||
1441 | } | ||
1442 | if (ar->phy_heavy_clip & 0xf) { | ||
1443 | ar->power_2G_ht20[0]++; | ||
1444 | ar->power_2G_ht20[1]++; | ||
1445 | ar->power_2G_ht20[2]++; | ||
1446 | } | ||
1447 | |||
1448 | |||
1393 | #undef EDGES | 1449 | #undef EDGES |
1394 | } | 1450 | } |
1395 | 1451 | ||
@@ -1499,8 +1555,6 @@ static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) | |||
1499 | /* calc. conformance test limits and apply to ar->power*[] */ | 1555 | /* calc. conformance test limits and apply to ar->power*[] */ |
1500 | ar9170_calc_ctl(ar, freq, bw); | 1556 | ar9170_calc_ctl(ar, freq, bw); |
1501 | 1557 | ||
1502 | /* TODO: (heavy clip) regulatory domain power level fine-tuning. */ | ||
1503 | |||
1504 | /* set ACK/CTS TX power */ | 1558 | /* set ACK/CTS TX power */ |
1505 | ar9170_regwrite_begin(ar); | 1559 | ar9170_regwrite_begin(ar); |
1506 | 1560 | ||
@@ -1643,6 +1697,17 @@ int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, | |||
1643 | if (err) | 1697 | if (err) |
1644 | return err; | 1698 | return err; |
1645 | 1699 | ||
1700 | if (ar->phy_heavy_clip) { | ||
1701 | err = ar9170_write_reg(ar, 0x1c59e0, | ||
1702 | 0x200 | ar->phy_heavy_clip); | ||
1703 | if (err) { | ||
1704 | if (ar9170_nag_limiter(ar)) | ||
1705 | printk(KERN_ERR "%s: failed to set " | ||
1706 | "heavy clip\n", | ||
1707 | wiphy_name(ar->hw->wiphy)); | ||
1708 | } | ||
1709 | } | ||
1710 | |||
1646 | for (i = 0; i < 2; i++) { | 1711 | for (i = 0; i < 2; i++) { |
1647 | ar->noise[i] = ar9170_calc_noise_dbm( | 1712 | ar->noise[i] = ar9170_calc_noise_dbm( |
1648 | (le32_to_cpu(vals[2 + i]) >> 19) & 0x1ff); | 1713 | (le32_to_cpu(vals[2 + i]) >> 19) & 0x1ff); |