diff options
author | Vasanthakumar Thiagarajan <vasanth@atheros.com> | 2010-09-02 04:34:43 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-09-07 13:54:33 -0400 |
commit | 102885a5d114abad8f9d4101f94ce5b28c232231 (patch) | |
tree | 6399041d50d2e8b2681ed79f8d27205f160caa16 | |
parent | 21cc630f47d8589a42d563e89be4c631edbe8716 (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.h | 56 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/init.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/recv.c | 545 |
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 { | |||
481 | void ath_init_leds(struct ath_softc *sc); | 481 | void ath_init_leds(struct ath_softc *sc); |
482 | void ath_deinit_leds(struct ath_softc *sc); | 482 | void 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 | |||
503 | enum 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 | |||
510 | struct 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 | ||
602 | struct ath_wiphy { | 658 | struct 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 | ||
536 | static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, | 539 | static 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 | ||
22 | static 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 | |||
22 | static inline bool ath9k_check_auto_sleep(struct ath_softc *sc) | 31 | static 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 | ||
1088 | static 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 | |||
1143 | static 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 | |||
1342 | void 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 */ | ||
1388 | static 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 | |||
1608 | div_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 | |||
1079 | int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) | 1621 | int 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 | ||
1218 | requeue: | 1763 | requeue: |