aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVasanthakumar Thiagarajan <vasanth@atheros.com>2010-09-02 04:34:43 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-09-07 13:54:33 -0400
commit102885a5d114abad8f9d4101f94ce5b28c232231 (patch)
tree6399041d50d2e8b2681ed79f8d27205f160caa16
parent21cc630f47d8589a42d563e89be4c631edbe8716 (diff)
ath9k: Implement an algorithm for Antenna diversity and combining
This algorithm chooses the best main and alt lna out of LNA1, LNA2, LNA1+LNA2 and LNA1-LNA2 to improve rx for single chain chips(AR9285). This would greatly improve rx when there is only one antenna is connected with AR9285. Signed-off-by: Vasanthakumar Thiagarajan <vasanth@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h56
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c545
3 files changed, 604 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index f0197a6046ab..5fe570bb5c4c 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -481,6 +481,60 @@ struct ath_led {
481void ath_init_leds(struct ath_softc *sc); 481void ath_init_leds(struct ath_softc *sc);
482void ath_deinit_leds(struct ath_softc *sc); 482void ath_deinit_leds(struct ath_softc *sc);
483 483
484/* Antenna diversity/combining */
485#define ATH_ANT_RX_CURRENT_SHIFT 4
486#define ATH_ANT_RX_MAIN_SHIFT 2
487#define ATH_ANT_RX_MASK 0x3
488
489#define ATH_ANT_DIV_COMB_SHORT_SCAN_INTR 50
490#define ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT 0x100
491#define ATH_ANT_DIV_COMB_MAX_PKTCOUNT 0x200
492#define ATH_ANT_DIV_COMB_INIT_COUNT 95
493#define ATH_ANT_DIV_COMB_MAX_COUNT 100
494#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO 30
495#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO2 20
496
497#define ATH_ANT_DIV_COMB_LNA1_LNA2_DELTA -3
498#define ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA -1
499#define ATH_ANT_DIV_COMB_LNA1_DELTA_HI -4
500#define ATH_ANT_DIV_COMB_LNA1_DELTA_MID -2
501#define ATH_ANT_DIV_COMB_LNA1_DELTA_LOW 2
502
503enum ath9k_ant_div_comb_lna_conf {
504 ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2,
505 ATH_ANT_DIV_COMB_LNA2,
506 ATH_ANT_DIV_COMB_LNA1,
507 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2,
508};
509
510struct ath_ant_comb {
511 u16 count;
512 u16 total_pkt_count;
513 bool scan;
514 bool scan_not_start;
515 int main_total_rssi;
516 int alt_total_rssi;
517 int alt_recv_cnt;
518 int main_recv_cnt;
519 int rssi_lna1;
520 int rssi_lna2;
521 int rssi_add;
522 int rssi_sub;
523 int rssi_first;
524 int rssi_second;
525 int rssi_third;
526 bool alt_good;
527 int quick_scan_cnt;
528 int main_conf;
529 enum ath9k_ant_div_comb_lna_conf first_quick_scan_conf;
530 enum ath9k_ant_div_comb_lna_conf second_quick_scan_conf;
531 int first_bias;
532 int second_bias;
533 bool first_ratio;
534 bool second_ratio;
535 unsigned long scan_start_time;
536};
537
484/********************/ 538/********************/
485/* Main driver core */ 539/* Main driver core */
486/********************/ 540/********************/
@@ -597,6 +651,8 @@ struct ath_softc {
597 struct ath_btcoex btcoex; 651 struct ath_btcoex btcoex;
598 652
599 struct ath_descdma txsdma; 653 struct ath_descdma txsdma;
654
655 struct ath_ant_comb ant_comb;
600}; 656};
601 657
602struct ath_wiphy { 658struct ath_wiphy {
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 3dbff8d07766..e7c07b3370cc 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -531,6 +531,9 @@ static void ath9k_init_misc(struct ath_softc *sc)
531 sc->beacon.bslot[i] = NULL; 531 sc->beacon.bslot[i] = NULL;
532 sc->beacon.bslot_aphy[i] = NULL; 532 sc->beacon.bslot_aphy[i] = NULL;
533 } 533 }
534
535 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)
536 sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT;
534} 537}
535 538
536static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, 539static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 534a91bcc1d9..b32c8f033d20 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -19,6 +19,15 @@
19 19
20#define SKB_CB_ATHBUF(__skb) (*((struct ath_buf **)__skb->cb)) 20#define SKB_CB_ATHBUF(__skb) (*((struct ath_buf **)__skb->cb))
21 21
22static inline bool ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta,
23 int mindelta, int main_rssi_avg,
24 int alt_rssi_avg, int pkt_count)
25{
26 return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
27 (alt_rssi_avg > main_rssi_avg + maxdelta)) ||
28 (alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50);
29}
30
22static inline bool ath9k_check_auto_sleep(struct ath_softc *sc) 31static inline bool ath9k_check_auto_sleep(struct ath_softc *sc)
23{ 32{
24 return sc->ps_enabled && 33 return sc->ps_enabled &&
@@ -1076,6 +1085,539 @@ static void ath9k_rx_skb_postprocess(struct ath_common *common,
1076 rxs->flag &= ~RX_FLAG_DECRYPTED; 1085 rxs->flag &= ~RX_FLAG_DECRYPTED;
1077} 1086}
1078 1087
1088static void ath_lnaconf_alt_good_scan(struct ath_ant_comb *antcomb,
1089 struct ath_hw_antcomb_conf ant_conf,
1090 int main_rssi_avg)
1091{
1092 antcomb->quick_scan_cnt = 0;
1093
1094 if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
1095 antcomb->rssi_lna2 = main_rssi_avg;
1096 else if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA1)
1097 antcomb->rssi_lna1 = main_rssi_avg;
1098
1099 switch ((ant_conf.main_lna_conf << 4) | ant_conf.alt_lna_conf) {
1100 case (0x10): /* LNA2 A-B */
1101 antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
1102 antcomb->first_quick_scan_conf =
1103 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
1104 antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
1105 break;
1106 case (0x20): /* LNA1 A-B */
1107 antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
1108 antcomb->first_quick_scan_conf =
1109 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
1110 antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
1111 break;
1112 case (0x21): /* LNA1 LNA2 */
1113 antcomb->main_conf = ATH_ANT_DIV_COMB_LNA2;
1114 antcomb->first_quick_scan_conf =
1115 ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
1116 antcomb->second_quick_scan_conf =
1117 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
1118 break;
1119 case (0x12): /* LNA2 LNA1 */
1120 antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1;
1121 antcomb->first_quick_scan_conf =
1122 ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
1123 antcomb->second_quick_scan_conf =
1124 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
1125 break;
1126 case (0x13): /* LNA2 A+B */
1127 antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
1128 antcomb->first_quick_scan_conf =
1129 ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
1130 antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
1131 break;
1132 case (0x23): /* LNA1 A+B */
1133 antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
1134 antcomb->first_quick_scan_conf =
1135 ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
1136 antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
1137 break;
1138 default:
1139 break;
1140 }
1141}
1142
1143static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,
1144 struct ath_hw_antcomb_conf *div_ant_conf,
1145 int main_rssi_avg, int alt_rssi_avg,
1146 int alt_ratio)
1147{
1148 /* alt_good */
1149 switch (antcomb->quick_scan_cnt) {
1150 case 0:
1151 /* set alt to main, and alt to first conf */
1152 div_ant_conf->main_lna_conf = antcomb->main_conf;
1153 div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf;
1154 break;
1155 case 1:
1156 /* set alt to main, and alt to first conf */
1157 div_ant_conf->main_lna_conf = antcomb->main_conf;
1158 div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf;
1159 antcomb->rssi_first = main_rssi_avg;
1160 antcomb->rssi_second = alt_rssi_avg;
1161
1162 if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
1163 /* main is LNA1 */
1164 if (ath_is_alt_ant_ratio_better(alt_ratio,
1165 ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
1166 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
1167 main_rssi_avg, alt_rssi_avg,
1168 antcomb->total_pkt_count))
1169 antcomb->first_ratio = true;
1170 else
1171 antcomb->first_ratio = false;
1172 } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
1173 if (ath_is_alt_ant_ratio_better(alt_ratio,
1174 ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
1175 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
1176 main_rssi_avg, alt_rssi_avg,
1177 antcomb->total_pkt_count))
1178 antcomb->first_ratio = true;
1179 else
1180 antcomb->first_ratio = false;
1181 } else {
1182 if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
1183 (alt_rssi_avg > main_rssi_avg +
1184 ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
1185 (alt_rssi_avg > main_rssi_avg)) &&
1186 (antcomb->total_pkt_count > 50))
1187 antcomb->first_ratio = true;
1188 else
1189 antcomb->first_ratio = false;
1190 }
1191 break;
1192 case 2:
1193 antcomb->alt_good = false;
1194 antcomb->scan_not_start = false;
1195 antcomb->scan = false;
1196 antcomb->rssi_first = main_rssi_avg;
1197 antcomb->rssi_third = alt_rssi_avg;
1198
1199 if (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1)
1200 antcomb->rssi_lna1 = alt_rssi_avg;
1201 else if (antcomb->second_quick_scan_conf ==
1202 ATH_ANT_DIV_COMB_LNA2)
1203 antcomb->rssi_lna2 = alt_rssi_avg;
1204 else if (antcomb->second_quick_scan_conf ==
1205 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2) {
1206 if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)
1207 antcomb->rssi_lna2 = main_rssi_avg;
1208 else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1)
1209 antcomb->rssi_lna1 = main_rssi_avg;
1210 }
1211
1212 if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
1213 ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)
1214 div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
1215 else
1216 div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
1217
1218 if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
1219 if (ath_is_alt_ant_ratio_better(alt_ratio,
1220 ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
1221 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
1222 main_rssi_avg, alt_rssi_avg,
1223 antcomb->total_pkt_count))
1224 antcomb->second_ratio = true;
1225 else
1226 antcomb->second_ratio = false;
1227 } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
1228 if (ath_is_alt_ant_ratio_better(alt_ratio,
1229 ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
1230 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
1231 main_rssi_avg, alt_rssi_avg,
1232 antcomb->total_pkt_count))
1233 antcomb->second_ratio = true;
1234 else
1235 antcomb->second_ratio = false;
1236 } else {
1237 if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
1238 (alt_rssi_avg > main_rssi_avg +
1239 ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
1240 (alt_rssi_avg > main_rssi_avg)) &&
1241 (antcomb->total_pkt_count > 50))
1242 antcomb->second_ratio = true;
1243 else
1244 antcomb->second_ratio = false;
1245 }
1246
1247 /* set alt to the conf with maximun ratio */
1248 if (antcomb->first_ratio && antcomb->second_ratio) {
1249 if (antcomb->rssi_second > antcomb->rssi_third) {
1250 /* first alt*/
1251 if ((antcomb->first_quick_scan_conf ==
1252 ATH_ANT_DIV_COMB_LNA1) ||
1253 (antcomb->first_quick_scan_conf ==
1254 ATH_ANT_DIV_COMB_LNA2))
1255 /* Set alt LNA1 or LNA2*/
1256 if (div_ant_conf->main_lna_conf ==
1257 ATH_ANT_DIV_COMB_LNA2)
1258 div_ant_conf->alt_lna_conf =
1259 ATH_ANT_DIV_COMB_LNA1;
1260 else
1261 div_ant_conf->alt_lna_conf =
1262 ATH_ANT_DIV_COMB_LNA2;
1263 else
1264 /* Set alt to A+B or A-B */
1265 div_ant_conf->alt_lna_conf =
1266 antcomb->first_quick_scan_conf;
1267 } else if ((antcomb->second_quick_scan_conf ==
1268 ATH_ANT_DIV_COMB_LNA1) ||
1269 (antcomb->second_quick_scan_conf ==
1270 ATH_ANT_DIV_COMB_LNA2)) {
1271 /* Set alt LNA1 or LNA2 */
1272 if (div_ant_conf->main_lna_conf ==
1273 ATH_ANT_DIV_COMB_LNA2)
1274 div_ant_conf->alt_lna_conf =
1275 ATH_ANT_DIV_COMB_LNA1;
1276 else
1277 div_ant_conf->alt_lna_conf =
1278 ATH_ANT_DIV_COMB_LNA2;
1279 } else {
1280 /* Set alt to A+B or A-B */
1281 div_ant_conf->alt_lna_conf =
1282 antcomb->second_quick_scan_conf;
1283 }
1284 } else if (antcomb->first_ratio) {
1285 /* first alt */
1286 if ((antcomb->first_quick_scan_conf ==
1287 ATH_ANT_DIV_COMB_LNA1) ||
1288 (antcomb->first_quick_scan_conf ==
1289 ATH_ANT_DIV_COMB_LNA2))
1290 /* Set alt LNA1 or LNA2 */
1291 if (div_ant_conf->main_lna_conf ==
1292 ATH_ANT_DIV_COMB_LNA2)
1293 div_ant_conf->alt_lna_conf =
1294 ATH_ANT_DIV_COMB_LNA1;
1295 else
1296 div_ant_conf->alt_lna_conf =
1297 ATH_ANT_DIV_COMB_LNA2;
1298 else
1299 /* Set alt to A+B or A-B */
1300 div_ant_conf->alt_lna_conf =
1301 antcomb->first_quick_scan_conf;
1302 } else if (antcomb->second_ratio) {
1303 /* second alt */
1304 if ((antcomb->second_quick_scan_conf ==
1305 ATH_ANT_DIV_COMB_LNA1) ||
1306 (antcomb->second_quick_scan_conf ==
1307 ATH_ANT_DIV_COMB_LNA2))
1308 /* Set alt LNA1 or LNA2 */
1309 if (div_ant_conf->main_lna_conf ==
1310 ATH_ANT_DIV_COMB_LNA2)
1311 div_ant_conf->alt_lna_conf =
1312 ATH_ANT_DIV_COMB_LNA1;
1313 else
1314 div_ant_conf->alt_lna_conf =
1315 ATH_ANT_DIV_COMB_LNA2;
1316 else
1317 /* Set alt to A+B or A-B */
1318 div_ant_conf->alt_lna_conf =
1319 antcomb->second_quick_scan_conf;
1320 } else {
1321 /* main is largest */
1322 if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) ||
1323 (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2))
1324 /* Set alt LNA1 or LNA2 */
1325 if (div_ant_conf->main_lna_conf ==
1326 ATH_ANT_DIV_COMB_LNA2)
1327 div_ant_conf->alt_lna_conf =
1328 ATH_ANT_DIV_COMB_LNA1;
1329 else
1330 div_ant_conf->alt_lna_conf =
1331 ATH_ANT_DIV_COMB_LNA2;
1332 else
1333 /* Set alt to A+B or A-B */
1334 div_ant_conf->alt_lna_conf = antcomb->main_conf;
1335 }
1336 break;
1337 default:
1338 break;
1339 }
1340}
1341
1342void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf)
1343{
1344 /* Adjust the fast_div_bias based on main and alt lna conf */
1345 switch ((ant_conf->main_lna_conf << 4) | ant_conf->alt_lna_conf) {
1346 case (0x01): /* A-B LNA2 */
1347 ant_conf->fast_div_bias = 0x3b;
1348 break;
1349 case (0x02): /* A-B LNA1 */
1350 ant_conf->fast_div_bias = 0x3d;
1351 break;
1352 case (0x03): /* A-B A+B */
1353 ant_conf->fast_div_bias = 0x1;
1354 break;
1355 case (0x10): /* LNA2 A-B */
1356 ant_conf->fast_div_bias = 0x7;
1357 break;
1358 case (0x12): /* LNA2 LNA1 */
1359 ant_conf->fast_div_bias = 0x2;
1360 break;
1361 case (0x13): /* LNA2 A+B */
1362 ant_conf->fast_div_bias = 0x7;
1363 break;
1364 case (0x20): /* LNA1 A-B */
1365 ant_conf->fast_div_bias = 0x6;
1366 break;
1367 case (0x21): /* LNA1 LNA2 */
1368 ant_conf->fast_div_bias = 0x0;
1369 break;
1370 case (0x23): /* LNA1 A+B */
1371 ant_conf->fast_div_bias = 0x6;
1372 break;
1373 case (0x30): /* A+B A-B */
1374 ant_conf->fast_div_bias = 0x1;
1375 break;
1376 case (0x31): /* A+B LNA2 */
1377 ant_conf->fast_div_bias = 0x3b;
1378 break;
1379 case (0x32): /* A+B LNA1 */
1380 ant_conf->fast_div_bias = 0x3d;
1381 break;
1382 default:
1383 break;
1384 }
1385}
1386
1387/* Antenna diversity and combining */
1388static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
1389{
1390 struct ath_hw_antcomb_conf div_ant_conf;
1391 struct ath_ant_comb *antcomb = &sc->ant_comb;
1392 int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
1393 int curr_main_set, curr_bias;
1394 int main_rssi = rs->rs_rssi_ctl0;
1395 int alt_rssi = rs->rs_rssi_ctl1;
1396 int rx_ant_conf, main_ant_conf;
1397 bool short_scan = false;
1398
1399 rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
1400 ATH_ANT_RX_MASK;
1401 main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
1402 ATH_ANT_RX_MASK;
1403
1404 /* Record packet only when alt_rssi is positive */
1405 if (alt_rssi > 0) {
1406 antcomb->total_pkt_count++;
1407 antcomb->main_total_rssi += main_rssi;
1408 antcomb->alt_total_rssi += alt_rssi;
1409 if (main_ant_conf == rx_ant_conf)
1410 antcomb->main_recv_cnt++;
1411 else
1412 antcomb->alt_recv_cnt++;
1413 }
1414
1415 /* Short scan check */
1416 if (antcomb->scan && antcomb->alt_good) {
1417 if (time_after(jiffies, antcomb->scan_start_time +
1418 msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
1419 short_scan = true;
1420 else
1421 if (antcomb->total_pkt_count ==
1422 ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
1423 alt_ratio = ((antcomb->alt_recv_cnt * 100) /
1424 antcomb->total_pkt_count);
1425 if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
1426 short_scan = true;
1427 }
1428 }
1429
1430 if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
1431 rs->rs_moreaggr) && !short_scan)
1432 return;
1433
1434 if (antcomb->total_pkt_count) {
1435 alt_ratio = ((antcomb->alt_recv_cnt * 100) /
1436 antcomb->total_pkt_count);
1437 main_rssi_avg = (antcomb->main_total_rssi /
1438 antcomb->total_pkt_count);
1439 alt_rssi_avg = (antcomb->alt_total_rssi /
1440 antcomb->total_pkt_count);
1441 }
1442
1443
1444 ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
1445 curr_alt_set = div_ant_conf.alt_lna_conf;
1446 curr_main_set = div_ant_conf.main_lna_conf;
1447 curr_bias = div_ant_conf.fast_div_bias;
1448
1449 antcomb->count++;
1450
1451 if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
1452 if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
1453 ath_lnaconf_alt_good_scan(antcomb, div_ant_conf,
1454 main_rssi_avg);
1455 antcomb->alt_good = true;
1456 } else {
1457 antcomb->alt_good = false;
1458 }
1459
1460 antcomb->count = 0;
1461 antcomb->scan = true;
1462 antcomb->scan_not_start = true;
1463 }
1464
1465 if (!antcomb->scan) {
1466 if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
1467 if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
1468 /* Switch main and alt LNA */
1469 div_ant_conf.main_lna_conf =
1470 ATH_ANT_DIV_COMB_LNA2;
1471 div_ant_conf.alt_lna_conf =
1472 ATH_ANT_DIV_COMB_LNA1;
1473 } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
1474 div_ant_conf.main_lna_conf =
1475 ATH_ANT_DIV_COMB_LNA1;
1476 div_ant_conf.alt_lna_conf =
1477 ATH_ANT_DIV_COMB_LNA2;
1478 }
1479
1480 goto div_comb_done;
1481 } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
1482 (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
1483 /* Set alt to another LNA */
1484 if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
1485 div_ant_conf.alt_lna_conf =
1486 ATH_ANT_DIV_COMB_LNA1;
1487 else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
1488 div_ant_conf.alt_lna_conf =
1489 ATH_ANT_DIV_COMB_LNA2;
1490
1491 goto div_comb_done;
1492 }
1493
1494 if ((alt_rssi_avg < (main_rssi_avg +
1495 ATH_ANT_DIV_COMB_LNA1_LNA2_DELTA)))
1496 goto div_comb_done;
1497 }
1498
1499 if (!antcomb->scan_not_start) {
1500 switch (curr_alt_set) {
1501 case ATH_ANT_DIV_COMB_LNA2:
1502 antcomb->rssi_lna2 = alt_rssi_avg;
1503 antcomb->rssi_lna1 = main_rssi_avg;
1504 antcomb->scan = true;
1505 /* set to A+B */
1506 div_ant_conf.main_lna_conf =
1507 ATH_ANT_DIV_COMB_LNA1;
1508 div_ant_conf.alt_lna_conf =
1509 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
1510 break;
1511 case ATH_ANT_DIV_COMB_LNA1:
1512 antcomb->rssi_lna1 = alt_rssi_avg;
1513 antcomb->rssi_lna2 = main_rssi_avg;
1514 antcomb->scan = true;
1515 /* set to A+B */
1516 div_ant_conf.main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
1517 div_ant_conf.alt_lna_conf =
1518 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
1519 break;
1520 case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
1521 antcomb->rssi_add = alt_rssi_avg;
1522 antcomb->scan = true;
1523 /* set to A-B */
1524 div_ant_conf.alt_lna_conf =
1525 ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
1526 break;
1527 case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
1528 antcomb->rssi_sub = alt_rssi_avg;
1529 antcomb->scan = false;
1530 if (antcomb->rssi_lna2 >
1531 (antcomb->rssi_lna1 +
1532 ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
1533 /* use LNA2 as main LNA */
1534 if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
1535 (antcomb->rssi_add > antcomb->rssi_sub)) {
1536 /* set to A+B */
1537 div_ant_conf.main_lna_conf =
1538 ATH_ANT_DIV_COMB_LNA2;
1539 div_ant_conf.alt_lna_conf =
1540 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
1541 } else if (antcomb->rssi_sub >
1542 antcomb->rssi_lna1) {
1543 /* set to A-B */
1544 div_ant_conf.main_lna_conf =
1545 ATH_ANT_DIV_COMB_LNA2;
1546 div_ant_conf.alt_lna_conf =
1547 ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
1548 } else {
1549 /* set to LNA1 */
1550 div_ant_conf.main_lna_conf =
1551 ATH_ANT_DIV_COMB_LNA2;
1552 div_ant_conf.alt_lna_conf =
1553 ATH_ANT_DIV_COMB_LNA1;
1554 }
1555 } else {
1556 /* use LNA1 as main LNA */
1557 if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
1558 (antcomb->rssi_add > antcomb->rssi_sub)) {
1559 /* set to A+B */
1560 div_ant_conf.main_lna_conf =
1561 ATH_ANT_DIV_COMB_LNA1;
1562 div_ant_conf.alt_lna_conf =
1563 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
1564 } else if (antcomb->rssi_sub >
1565 antcomb->rssi_lna1) {
1566 /* set to A-B */
1567 div_ant_conf.main_lna_conf =
1568 ATH_ANT_DIV_COMB_LNA1;
1569 div_ant_conf.alt_lna_conf =
1570 ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
1571 } else {
1572 /* set to LNA2 */
1573 div_ant_conf.main_lna_conf =
1574 ATH_ANT_DIV_COMB_LNA1;
1575 div_ant_conf.alt_lna_conf =
1576 ATH_ANT_DIV_COMB_LNA2;
1577 }
1578 }
1579 break;
1580 default:
1581 break;
1582 }
1583 } else {
1584 if (!antcomb->alt_good) {
1585 antcomb->scan_not_start = false;
1586 /* Set alt to another LNA */
1587 if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
1588 div_ant_conf.main_lna_conf =
1589 ATH_ANT_DIV_COMB_LNA2;
1590 div_ant_conf.alt_lna_conf =
1591 ATH_ANT_DIV_COMB_LNA1;
1592 } else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
1593 div_ant_conf.main_lna_conf =
1594 ATH_ANT_DIV_COMB_LNA1;
1595 div_ant_conf.alt_lna_conf =
1596 ATH_ANT_DIV_COMB_LNA2;
1597 }
1598 goto div_comb_done;
1599 }
1600 }
1601
1602 ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
1603 main_rssi_avg, alt_rssi_avg,
1604 alt_ratio);
1605
1606 antcomb->quick_scan_cnt++;
1607
1608div_comb_done:
1609 ath_ant_div_conf_fast_divbias(&div_ant_conf);
1610
1611 ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
1612
1613 antcomb->scan_start_time = jiffies;
1614 antcomb->total_pkt_count = 0;
1615 antcomb->main_total_rssi = 0;
1616 antcomb->alt_total_rssi = 0;
1617 antcomb->main_recv_cnt = 0;
1618 antcomb->alt_recv_cnt = 0;
1619}
1620
1079int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) 1621int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
1080{ 1622{
1081 struct ath_buf *bf; 1623 struct ath_buf *bf;
@@ -1213,6 +1755,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
1213 PS_WAIT_FOR_PSPOLL_DATA)))) 1755 PS_WAIT_FOR_PSPOLL_DATA))))
1214 ath_rx_ps(sc, skb); 1756 ath_rx_ps(sc, skb);
1215 1757
1758 if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)
1759 ath_ant_comb_scan(sc, &rs);
1760
1216 ath_rx_send_to_mac80211(hw, sc, skb, rxs); 1761 ath_rx_send_to_mac80211(hw, sc, skb, rxs);
1217 1762
1218requeue: 1763requeue: