diff --git a/sys/conf/files b/sys/conf/files index 9414851c6838..f3c600f70340 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -733,6 +733,8 @@ dev/ath/if_ath_keycache.c optional ath \ compile-with "${NORMAL_C} -I$S/dev/ath" dev/ath/if_ath_led.c optional ath \ compile-with "${NORMAL_C} -I$S/dev/ath" +dev/ath/if_ath_lna_div.c optional ath \ + compile-with "${NORMAL_C} -I$S/dev/ath" dev/ath/if_ath_tx.c optional ath \ compile-with "${NORMAL_C} -I$S/dev/ath" dev/ath/if_ath_tx_edma.c optional ath \ diff --git a/sys/dev/ath/ath_hal/ah.h b/sys/dev/ath/ath_hal/ah.h index bd26dba45e7b..2480803300d2 100644 --- a/sys/dev/ath/ath_hal/ah.h +++ b/sys/dev/ath/ath_hal/ah.h @@ -1402,9 +1402,6 @@ struct ath_hal { const struct ieee80211_channel *); void __ahdecl(*ah_procMibEvent)(struct ath_hal *, const HAL_NODE_STATS *); - void __ahdecl(*ah_rxAntCombDiversity)(struct ath_hal *, - struct ath_rx_status *, - unsigned long, int); /* Misc Functions */ HAL_STATUS __ahdecl(*ah_getCapability)(struct ath_hal *, @@ -1585,6 +1582,12 @@ struct ath_hal { uint32_t, uint32_t); void __ahdecl(*ah_btCoexDisable)(struct ath_hal *); int __ahdecl(*ah_btCoexEnable)(struct ath_hal *); + + /* LNA diversity configuration */ + void __ahdecl(*ah_divLnaConfGet)(struct ath_hal *, + HAL_ANT_COMB_CONFIG *); + void __ahdecl(*ah_divLnaConfSet)(struct ath_hal *, + HAL_ANT_COMB_CONFIG *); }; /* diff --git a/sys/dev/ath/ath_hal/ar9002/ar9285.h b/sys/dev/ath/ath_hal/ar9002/ar9285.h index 31b5f64a4496..b37b29781451 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9285.h +++ b/sys/dev/ath/ath_hal/ar9002/ar9285.h @@ -20,42 +20,12 @@ #include "ar5416/ar5416.h" -struct ar9285_ant_comb { - uint16_t count; - uint16_t total_pkt_count; - HAL_BOOL scan; - HAL_BOOL scan_not_start; - int main_total_rssi; - int alt_total_rssi; - int alt_recv_cnt; - int main_recv_cnt; - int rssi_lna1; - int rssi_lna2; - int rssi_add; - int rssi_sub; - int rssi_first; - int rssi_second; - int rssi_third; - HAL_BOOL alt_good; - int quick_scan_cnt; - int main_conf; - HAL_ANT_DIV_COMB_LNA_CONF first_quick_scan_conf; - HAL_ANT_DIV_COMB_LNA_CONF second_quick_scan_conf; - int first_bias; - int second_bias; - HAL_BOOL first_ratio; - HAL_BOOL second_ratio; - unsigned long scan_start_time; -}; - struct ath_hal_9285 { struct ath_hal_5416 ah_5416; HAL_INI_ARRAY ah_ini_txgain; HAL_INI_ARRAY ah_ini_rxgain; - struct ar9285_ant_comb ant_comb; /* Kite Antenna comb/diversity */ - struct { int32_t prev_offset; /* Previous value of PA offset value */ int8_t max_skipcount; /* Max No. of times PACAL can be skipped */ @@ -71,7 +41,6 @@ struct ath_hal_9285 { #define AR_PHY_CCA_MIN_GOOD_VAL_9285_2GHZ -127 #define AR_PHY_CCA_MAX_GOOD_VAL_9285_2GHZ -108 -HAL_BOOL ar9285SetAntennaSwitch(struct ath_hal *, HAL_ANT_SETTING); HAL_BOOL ar9285RfAttach(struct ath_hal *, HAL_STATUS *); extern HAL_BOOL ar9285SetTransmitPower(struct ath_hal *, diff --git a/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c b/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c index 423f9de00f06..edb6f267d42b 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c @@ -180,6 +180,8 @@ ar9285Attach(uint16_t devid, HAL_SOFTC sc, ah->ah_setTxPower = ar9285SetTransmitPower; ah->ah_setBoardValues = ar9285SetBoardValues; ah->ah_btCoexSetParameter = ar9285BTCoexSetParameter; + ah->ah_divLnaConfGet = ar9285_antdiv_comb_conf_get; + ah->ah_divLnaConfSet = ar9285_antdiv_comb_conf_set; AH5416(ah)->ah_cal.iqCalData.calData = &ar9280_iq_cal; AH5416(ah)->ah_cal.adcGainCalData.calData = &ar9280_adc_gain_cal; @@ -341,7 +343,6 @@ ar9285Attach(uint16_t devid, HAL_SOFTC sc, /* Print out whether the EEPROM settings enable AR9285 diversity */ if (ar9285_check_div_comb(ah)) { ath_hal_printf(ah, "[ath] Enabling diversity for Kite\n"); - ah->ah_rxAntCombDiversity = ar9285_ant_comb_scan; } /* Disable 11n for the AR2427 */ diff --git a/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.c b/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.c index fa7e49b76413..5fd01b75572e 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.c @@ -33,609 +33,13 @@ #include "ah_eeprom_v4k.h" #include "ar9002/ar9280.h" -#include "ar9002/ar9285_diversity.h" #include "ar9002/ar9285.h" #include "ar5416/ar5416reg.h" #include "ar5416/ar5416phy.h" #include "ar9002/ar9285phy.h" #include "ar9002/ar9285_phy.h" - -/* Linux compability macros */ -/* - * XXX these don't handle rounding, underflow, overflow, wrapping! - */ -#define msecs_to_jiffies(a) ( (a) * hz / 1000 ) -#define time_after(a, b) ( (long) (b) - (long) (a) < 0 ) - -static HAL_BOOL -ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta, int mindelta, - int main_rssi_avg, int alt_rssi_avg, int pkt_count) -{ - return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) && - (alt_rssi_avg > main_rssi_avg + maxdelta)) || - (alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50); -} - -static void -ath_lnaconf_alt_good_scan(struct ar9285_ant_comb *antcomb, - HAL_ANT_COMB_CONFIG *ant_conf, int main_rssi_avg) -{ - antcomb->quick_scan_cnt = 0; - - if (ant_conf->main_lna_conf == HAL_ANT_DIV_COMB_LNA2) - antcomb->rssi_lna2 = main_rssi_avg; - else if (ant_conf->main_lna_conf == HAL_ANT_DIV_COMB_LNA1) - antcomb->rssi_lna1 = main_rssi_avg; - - switch ((ant_conf->main_lna_conf << 4) | ant_conf->alt_lna_conf) { - case (0x10): /* LNA2 A-B */ - antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; - antcomb->first_quick_scan_conf = - HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; - antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA1; - break; - case (0x20): /* LNA1 A-B */ - antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; - antcomb->first_quick_scan_conf = - HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; - antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA2; - break; - case (0x21): /* LNA1 LNA2 */ - antcomb->main_conf = HAL_ANT_DIV_COMB_LNA2; - antcomb->first_quick_scan_conf = - HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; - antcomb->second_quick_scan_conf = - HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; - break; - case (0x12): /* LNA2 LNA1 */ - antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1; - antcomb->first_quick_scan_conf = - HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; - antcomb->second_quick_scan_conf = - HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; - break; - case (0x13): /* LNA2 A+B */ - antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; - antcomb->first_quick_scan_conf = - HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; - antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA1; - break; - case (0x23): /* LNA1 A+B */ - antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; - antcomb->first_quick_scan_conf = - HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; - antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA2; - break; - default: - break; - } -} - -static void -ath_select_ant_div_from_quick_scan(struct ar9285_ant_comb *antcomb, - HAL_ANT_COMB_CONFIG *div_ant_conf, int main_rssi_avg, - int alt_rssi_avg, int alt_ratio) -{ - /* alt_good */ - switch (antcomb->quick_scan_cnt) { - case 0: - /* set alt to main, and alt to first conf */ - div_ant_conf->main_lna_conf = antcomb->main_conf; - div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf; - break; - case 1: - /* set alt to main, and alt to first conf */ - div_ant_conf->main_lna_conf = antcomb->main_conf; - div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf; - antcomb->rssi_first = main_rssi_avg; - antcomb->rssi_second = alt_rssi_avg; - - if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) { - /* main is LNA1 */ - if (ath_is_alt_ant_ratio_better(alt_ratio, - ATH_ANT_DIV_COMB_LNA1_DELTA_HI, - ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, - main_rssi_avg, alt_rssi_avg, - antcomb->total_pkt_count)) - antcomb->first_ratio = AH_TRUE; - else - antcomb->first_ratio = AH_FALSE; - } else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2) { - if (ath_is_alt_ant_ratio_better(alt_ratio, - ATH_ANT_DIV_COMB_LNA1_DELTA_MID, - ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, - main_rssi_avg, alt_rssi_avg, - antcomb->total_pkt_count)) - antcomb->first_ratio = AH_TRUE; - else - antcomb->first_ratio = AH_FALSE; - } else { - if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) && - (alt_rssi_avg > main_rssi_avg + - ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) || - (alt_rssi_avg > main_rssi_avg)) && - (antcomb->total_pkt_count > 50)) - antcomb->first_ratio = AH_TRUE; - else - antcomb->first_ratio = AH_FALSE; - } - break; - case 2: - antcomb->alt_good = AH_FALSE; - antcomb->scan_not_start = AH_FALSE; - antcomb->scan = AH_FALSE; - antcomb->rssi_first = main_rssi_avg; - antcomb->rssi_third = alt_rssi_avg; - - if (antcomb->second_quick_scan_conf == HAL_ANT_DIV_COMB_LNA1) - antcomb->rssi_lna1 = alt_rssi_avg; - else if (antcomb->second_quick_scan_conf == - HAL_ANT_DIV_COMB_LNA2) - antcomb->rssi_lna2 = alt_rssi_avg; - else if (antcomb->second_quick_scan_conf == - HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2) { - if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2) - antcomb->rssi_lna2 = main_rssi_avg; - else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) - antcomb->rssi_lna1 = main_rssi_avg; - } - - if (antcomb->rssi_lna2 > antcomb->rssi_lna1 + - ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA) - div_ant_conf->main_lna_conf = HAL_ANT_DIV_COMB_LNA2; - else - div_ant_conf->main_lna_conf = HAL_ANT_DIV_COMB_LNA1; - - if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) { - if (ath_is_alt_ant_ratio_better(alt_ratio, - ATH_ANT_DIV_COMB_LNA1_DELTA_HI, - ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, - main_rssi_avg, alt_rssi_avg, - antcomb->total_pkt_count)) - antcomb->second_ratio = AH_TRUE; - else - antcomb->second_ratio = AH_FALSE; - } else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2) { - if (ath_is_alt_ant_ratio_better(alt_ratio, - ATH_ANT_DIV_COMB_LNA1_DELTA_MID, - ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, - main_rssi_avg, alt_rssi_avg, - antcomb->total_pkt_count)) - antcomb->second_ratio = AH_TRUE; - else - antcomb->second_ratio = AH_FALSE; - } else { - if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) && - (alt_rssi_avg > main_rssi_avg + - ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) || - (alt_rssi_avg > main_rssi_avg)) && - (antcomb->total_pkt_count > 50)) - antcomb->second_ratio = AH_TRUE; - else - antcomb->second_ratio = AH_FALSE; - } - - /* set alt to the conf with maximun ratio */ - if (antcomb->first_ratio && antcomb->second_ratio) { - if (antcomb->rssi_second > antcomb->rssi_third) { - /* first alt*/ - if ((antcomb->first_quick_scan_conf == - HAL_ANT_DIV_COMB_LNA1) || - (antcomb->first_quick_scan_conf == - HAL_ANT_DIV_COMB_LNA2)) - /* Set alt LNA1 or LNA2*/ - if (div_ant_conf->main_lna_conf == - HAL_ANT_DIV_COMB_LNA2) - div_ant_conf->alt_lna_conf = - HAL_ANT_DIV_COMB_LNA1; - else - div_ant_conf->alt_lna_conf = - HAL_ANT_DIV_COMB_LNA2; - else - /* Set alt to A+B or A-B */ - div_ant_conf->alt_lna_conf = - antcomb->first_quick_scan_conf; - } else if ((antcomb->second_quick_scan_conf == - HAL_ANT_DIV_COMB_LNA1) || - (antcomb->second_quick_scan_conf == - HAL_ANT_DIV_COMB_LNA2)) { - /* Set alt LNA1 or LNA2 */ - if (div_ant_conf->main_lna_conf == - HAL_ANT_DIV_COMB_LNA2) - div_ant_conf->alt_lna_conf = - HAL_ANT_DIV_COMB_LNA1; - else - div_ant_conf->alt_lna_conf = - HAL_ANT_DIV_COMB_LNA2; - } else { - /* Set alt to A+B or A-B */ - div_ant_conf->alt_lna_conf = - antcomb->second_quick_scan_conf; - } - } else if (antcomb->first_ratio) { - /* first alt */ - if ((antcomb->first_quick_scan_conf == - HAL_ANT_DIV_COMB_LNA1) || - (antcomb->first_quick_scan_conf == - HAL_ANT_DIV_COMB_LNA2)) - /* Set alt LNA1 or LNA2 */ - if (div_ant_conf->main_lna_conf == - HAL_ANT_DIV_COMB_LNA2) - div_ant_conf->alt_lna_conf = - HAL_ANT_DIV_COMB_LNA1; - else - div_ant_conf->alt_lna_conf = - HAL_ANT_DIV_COMB_LNA2; - else - /* Set alt to A+B or A-B */ - div_ant_conf->alt_lna_conf = - antcomb->first_quick_scan_conf; - } else if (antcomb->second_ratio) { - /* second alt */ - if ((antcomb->second_quick_scan_conf == - HAL_ANT_DIV_COMB_LNA1) || - (antcomb->second_quick_scan_conf == - HAL_ANT_DIV_COMB_LNA2)) - /* Set alt LNA1 or LNA2 */ - if (div_ant_conf->main_lna_conf == - HAL_ANT_DIV_COMB_LNA2) - div_ant_conf->alt_lna_conf = - HAL_ANT_DIV_COMB_LNA1; - else - div_ant_conf->alt_lna_conf = - HAL_ANT_DIV_COMB_LNA2; - else - /* Set alt to A+B or A-B */ - div_ant_conf->alt_lna_conf = - antcomb->second_quick_scan_conf; - } else { - /* main is largest */ - if ((antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) || - (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2)) - /* Set alt LNA1 or LNA2 */ - if (div_ant_conf->main_lna_conf == - HAL_ANT_DIV_COMB_LNA2) - div_ant_conf->alt_lna_conf = - HAL_ANT_DIV_COMB_LNA1; - else - div_ant_conf->alt_lna_conf = - HAL_ANT_DIV_COMB_LNA2; - else - /* Set alt to A+B or A-B */ - div_ant_conf->alt_lna_conf = antcomb->main_conf; - } - break; - default: - break; - } -} - -static void -ath_ant_div_conf_fast_divbias(HAL_ANT_COMB_CONFIG *ant_conf) -{ - /* Adjust the fast_div_bias based on main and alt lna conf */ - switch ((ant_conf->main_lna_conf << 4) | ant_conf->alt_lna_conf) { - case (0x01): /* A-B LNA2 */ - ant_conf->fast_div_bias = 0x3b; - break; - case (0x02): /* A-B LNA1 */ - ant_conf->fast_div_bias = 0x3d; - break; - case (0x03): /* A-B A+B */ - ant_conf->fast_div_bias = 0x1; - break; - case (0x10): /* LNA2 A-B */ - ant_conf->fast_div_bias = 0x7; - break; - case (0x12): /* LNA2 LNA1 */ - ant_conf->fast_div_bias = 0x2; - break; - case (0x13): /* LNA2 A+B */ - ant_conf->fast_div_bias = 0x7; - break; - case (0x20): /* LNA1 A-B */ - ant_conf->fast_div_bias = 0x6; - break; - case (0x21): /* LNA1 LNA2 */ - ant_conf->fast_div_bias = 0x0; - break; - case (0x23): /* LNA1 A+B */ - ant_conf->fast_div_bias = 0x6; - break; - case (0x30): /* A+B A-B */ - ant_conf->fast_div_bias = 0x1; - break; - case (0x31): /* A+B LNA2 */ - ant_conf->fast_div_bias = 0x3b; - break; - case (0x32): /* A+B LNA1 */ - ant_conf->fast_div_bias = 0x3d; - break; - default: - break; - } -} - -/* Antenna diversity and combining */ -void -ar9285_ant_comb_scan(struct ath_hal *ah, struct ath_rx_status *rs, - unsigned long ticks, int hz) -{ - HAL_ANT_COMB_CONFIG div_ant_conf; - struct ar9285_ant_comb *antcomb = &AH9285(ah)->ant_comb; - int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set; - int curr_main_set, curr_bias; - int main_rssi = rs->rs_rssi_ctl[0]; - int alt_rssi = rs->rs_rssi_ctl[1]; - int rx_ant_conf, main_ant_conf, alt_ant_conf; - HAL_BOOL short_scan = AH_FALSE; - - rx_ant_conf = (rs->rs_rssi_ctl[2] >> 4) & ATH_ANT_RX_MASK; - main_ant_conf = (rs->rs_rssi_ctl[2] >> 2) & ATH_ANT_RX_MASK; - alt_ant_conf = (rs->rs_rssi_ctl[2] >> 0) & ATH_ANT_RX_MASK; - -#if 0 - HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: RSSI %d/%d, conf %x/%x, rxconf %x, LNA: %d; ANT: %d; FastDiv: %d\n", - __func__, main_rssi, alt_rssi, main_ant_conf,alt_ant_conf, rx_ant_conf, - !!(rs->rs_rssi_ctl[2] & 0x80), !!(rs->rs_rssi_ctl[2] & 0x40), !!(rs->rs_rssi_ext[2] & 0x40)); -#endif - - if (! ar9285_check_div_comb(ah)) - return; - - if (AH5212(ah)->ah_diversity == AH_FALSE) - return; - -#if 0 - HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: main: %d, alt: %d, rx_ant_conf: %x, main_ant_conf: %x\n", - __func__, main_rssi, alt_rssi, rx_ant_conf, main_ant_conf); -#endif - - /* Record packet only when alt_rssi is positive */ - if (main_rssi > 0 && alt_rssi > 0) { - antcomb->total_pkt_count++; - antcomb->main_total_rssi += main_rssi; - antcomb->alt_total_rssi += alt_rssi; - if (main_ant_conf == rx_ant_conf) - antcomb->main_recv_cnt++; - else - antcomb->alt_recv_cnt++; - } - - /* Short scan check */ - if (antcomb->scan && antcomb->alt_good) { - if (time_after(ticks, antcomb->scan_start_time + - msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR))) - short_scan = AH_TRUE; - else - if (antcomb->total_pkt_count == - ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) { - alt_ratio = ((antcomb->alt_recv_cnt * 100) / - antcomb->total_pkt_count); - if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO) - short_scan = AH_TRUE; - } - } - - if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) || - rs->rs_moreaggr) && !short_scan) - return; - - if (antcomb->total_pkt_count) { - alt_ratio = ((antcomb->alt_recv_cnt * 100) / - antcomb->total_pkt_count); - main_rssi_avg = (antcomb->main_total_rssi / - antcomb->total_pkt_count); - alt_rssi_avg = (antcomb->alt_total_rssi / - antcomb->total_pkt_count); - } - - OS_MEMZERO(&div_ant_conf, sizeof(div_ant_conf)); - ar9285_antdiv_comb_conf_get(ah, &div_ant_conf); - curr_alt_set = div_ant_conf.alt_lna_conf; - curr_main_set = div_ant_conf.main_lna_conf; - curr_bias = div_ant_conf.fast_div_bias; - - antcomb->count++; - - if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) { - if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) { - ath_lnaconf_alt_good_scan(antcomb, &div_ant_conf, - main_rssi_avg); - antcomb->alt_good = AH_TRUE; - } else { - antcomb->alt_good = AH_FALSE; - } - - antcomb->count = 0; - antcomb->scan = AH_TRUE; - antcomb->scan_not_start = AH_TRUE; - } - - if (!antcomb->scan) { - if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) { - if (curr_alt_set == HAL_ANT_DIV_COMB_LNA2) { - /* Switch main and alt LNA */ - div_ant_conf.main_lna_conf = - HAL_ANT_DIV_COMB_LNA2; - div_ant_conf.alt_lna_conf = - HAL_ANT_DIV_COMB_LNA1; - } else if (curr_alt_set == HAL_ANT_DIV_COMB_LNA1) { - div_ant_conf.main_lna_conf = - HAL_ANT_DIV_COMB_LNA1; - div_ant_conf.alt_lna_conf = - HAL_ANT_DIV_COMB_LNA2; - } - - goto div_comb_done; - } else if ((curr_alt_set != HAL_ANT_DIV_COMB_LNA1) && - (curr_alt_set != HAL_ANT_DIV_COMB_LNA2)) { - /* Set alt to another LNA */ - if (curr_main_set == HAL_ANT_DIV_COMB_LNA2) - div_ant_conf.alt_lna_conf = - HAL_ANT_DIV_COMB_LNA1; - else if (curr_main_set == HAL_ANT_DIV_COMB_LNA1) - div_ant_conf.alt_lna_conf = - HAL_ANT_DIV_COMB_LNA2; - - goto div_comb_done; - } - - if ((alt_rssi_avg < (main_rssi_avg + - ATH_ANT_DIV_COMB_LNA1_LNA2_DELTA))) - goto div_comb_done; - } - - if (!antcomb->scan_not_start) { - switch (curr_alt_set) { - case HAL_ANT_DIV_COMB_LNA2: - antcomb->rssi_lna2 = alt_rssi_avg; - antcomb->rssi_lna1 = main_rssi_avg; - antcomb->scan = AH_TRUE; - /* set to A+B */ - div_ant_conf.main_lna_conf = - HAL_ANT_DIV_COMB_LNA1; - div_ant_conf.alt_lna_conf = - HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; - break; - case HAL_ANT_DIV_COMB_LNA1: - antcomb->rssi_lna1 = alt_rssi_avg; - antcomb->rssi_lna2 = main_rssi_avg; - antcomb->scan = AH_TRUE; - /* set to A+B */ - div_ant_conf.main_lna_conf = HAL_ANT_DIV_COMB_LNA2; - div_ant_conf.alt_lna_conf = - HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; - break; - case HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2: - antcomb->rssi_add = alt_rssi_avg; - antcomb->scan = AH_TRUE; - /* set to A-B */ - div_ant_conf.alt_lna_conf = - HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; - break; - case HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2: - antcomb->rssi_sub = alt_rssi_avg; - antcomb->scan = AH_FALSE; - if (antcomb->rssi_lna2 > - (antcomb->rssi_lna1 + - ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) { - /* use LNA2 as main LNA */ - if ((antcomb->rssi_add > antcomb->rssi_lna1) && - (antcomb->rssi_add > antcomb->rssi_sub)) { - /* set to A+B */ - div_ant_conf.main_lna_conf = - HAL_ANT_DIV_COMB_LNA2; - div_ant_conf.alt_lna_conf = - HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; - } else if (antcomb->rssi_sub > - antcomb->rssi_lna1) { - /* set to A-B */ - div_ant_conf.main_lna_conf = - HAL_ANT_DIV_COMB_LNA2; - div_ant_conf.alt_lna_conf = - HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; - } else { - /* set to LNA1 */ - div_ant_conf.main_lna_conf = - HAL_ANT_DIV_COMB_LNA2; - div_ant_conf.alt_lna_conf = - HAL_ANT_DIV_COMB_LNA1; - } - } else { - /* use LNA1 as main LNA */ - if ((antcomb->rssi_add > antcomb->rssi_lna2) && - (antcomb->rssi_add > antcomb->rssi_sub)) { - /* set to A+B */ - div_ant_conf.main_lna_conf = - HAL_ANT_DIV_COMB_LNA1; - div_ant_conf.alt_lna_conf = - HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; - } else if (antcomb->rssi_sub > - antcomb->rssi_lna1) { - /* set to A-B */ - div_ant_conf.main_lna_conf = - HAL_ANT_DIV_COMB_LNA1; - div_ant_conf.alt_lna_conf = - HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; - } else { - /* set to LNA2 */ - div_ant_conf.main_lna_conf = - HAL_ANT_DIV_COMB_LNA1; - div_ant_conf.alt_lna_conf = - HAL_ANT_DIV_COMB_LNA2; - } - } - break; - default: - break; - } - } else { - if (!antcomb->alt_good) { - antcomb->scan_not_start = AH_FALSE; - /* Set alt to another LNA */ - if (curr_main_set == HAL_ANT_DIV_COMB_LNA2) { - div_ant_conf.main_lna_conf = - HAL_ANT_DIV_COMB_LNA2; - div_ant_conf.alt_lna_conf = - HAL_ANT_DIV_COMB_LNA1; - } else if (curr_main_set == HAL_ANT_DIV_COMB_LNA1) { - div_ant_conf.main_lna_conf = - HAL_ANT_DIV_COMB_LNA1; - div_ant_conf.alt_lna_conf = - HAL_ANT_DIV_COMB_LNA2; - } - goto div_comb_done; - } - } - - ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf, - main_rssi_avg, alt_rssi_avg, - alt_ratio); - - antcomb->quick_scan_cnt++; - -div_comb_done: - ath_ant_div_conf_fast_divbias(&div_ant_conf); - - ar9285_antdiv_comb_conf_set(ah, &div_ant_conf); - - HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: total_pkt_count=%d\n", - __func__, antcomb->total_pkt_count); - - HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: main_total_rssi=%d\n", - __func__, antcomb->main_total_rssi); - HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: alt_total_rssi=%d\n", - __func__, antcomb->alt_total_rssi); - - HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: main_rssi_avg=%d\n", - __func__, main_rssi_avg); - HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: alt_alt_rssi_avg=%d\n", - __func__, alt_rssi_avg); - - HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: main_recv_cnt=%d\n", - __func__, antcomb->main_recv_cnt); - HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: alt_recv_cnt=%d\n", - __func__, antcomb->alt_recv_cnt); - -// if (curr_alt_set != div_ant_conf.alt_lna_conf) - HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: lna_conf: %x -> %x\n", - __func__, curr_alt_set, div_ant_conf.alt_lna_conf); -// if (curr_main_set != div_ant_conf.main_lna_conf) - HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: main_lna_conf: %x -> %x\n", - __func__, curr_main_set, div_ant_conf.main_lna_conf); -// if (curr_bias != div_ant_conf.fast_div_bias) - HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: fast_div_bias: %x -> %x\n", - __func__, curr_bias, div_ant_conf.fast_div_bias); - - antcomb->scan_start_time = ticks; - antcomb->total_pkt_count = 0; - antcomb->main_total_rssi = 0; - antcomb->alt_total_rssi = 0; - antcomb->main_recv_cnt = 0; - antcomb->alt_recv_cnt = 0; -} +#include "ar9002/ar9285_diversity.h" /* * Set the antenna switch to control RX antenna diversity. diff --git a/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.h b/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.h index 220db1e8126c..59d53b6f4609 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.h +++ b/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.h @@ -28,26 +28,6 @@ #ifndef __AR9285_DIVERSITY_H__ #define __AR9285_DIVERSITY_H__ -/* Antenna diversity/combining */ -#define ATH_ANT_RX_CURRENT_SHIFT 4 -#define ATH_ANT_RX_MAIN_SHIFT 2 -#define ATH_ANT_RX_MASK 0x3 - -#define ATH_ANT_DIV_COMB_SHORT_SCAN_INTR 50 -#define ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT 0x100 -#define ATH_ANT_DIV_COMB_MAX_PKTCOUNT 0x200 -#define ATH_ANT_DIV_COMB_INIT_COUNT 95 -#define ATH_ANT_DIV_COMB_MAX_COUNT 100 -#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO 30 -#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO2 20 - -#define ATH_ANT_DIV_COMB_LNA1_LNA2_DELTA -3 -#define ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA -1 -#define ATH_ANT_DIV_COMB_LNA1_DELTA_HI -4 -#define ATH_ANT_DIV_COMB_LNA1_DELTA_MID -2 -#define ATH_ANT_DIV_COMB_LNA1_DELTA_LOW 2 - -extern void ar9285_ant_comb_scan(struct ath_hal *ah, struct ath_rx_status *rs, - unsigned long ticks, int hz); +extern HAL_BOOL ar9285SetAntennaSwitch(struct ath_hal *, HAL_ANT_SETTING); #endif diff --git a/sys/dev/ath/ath_hal/ar9002/ar9285_reset.c b/sys/dev/ath/ath_hal/ar9002/ar9285_reset.c index 7a781bb6d738..cb5940fb77b5 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9285_reset.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9285_reset.c @@ -38,6 +38,7 @@ #include "ar9002/ar9002phy.h" #include "ar9002/ar9285phy.h" #include "ar9002/ar9285an.h" +#include "ar9002/ar9285_diversity.h" /* Eeprom versioning macros. Returns true if the version is equal or newer than the ver specified */ #define EEP_MINOR(_ah) \ diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c index 91c5bf652090..3c475857974f 100644 --- a/sys/dev/ath/if_ath.c +++ b/sys/dev/ath/if_ath.c @@ -113,6 +113,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #ifdef ATH_TX99_DIAG @@ -530,6 +531,14 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) goto bad2; } + /* Attach LNA diversity module */ + if (ath_lna_div_attach(sc) < 0) { + device_printf(sc->sc_dev, + "%s: unable to attach LNA diversity\n", __func__); + error = EIO; + goto bad2; + } + /* Start DFS processing tasklet */ TASK_INIT(&sc->sc_dfstask, 0, ath_dfs_tasklet, sc); @@ -680,6 +689,8 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) sc->sc_rxtsf32 = ath_hal_has_long_rxdesc_tsf(ah); sc->sc_hasenforcetxop = ath_hal_hasenforcetxop(ah); sc->sc_rx_lnamixer = ath_hal_hasrxlnamixer(ah); + sc->sc_hasdivcomb = ath_hal_hasdivantcomb(ah); + if (ath_hal_hasfastframes(ah)) ic->ic_caps |= IEEE80211_C_FF; wmodes = ath_hal_getwirelessmodes(ah); @@ -1038,6 +1049,7 @@ ath_detach(struct ath_softc *sc) #ifdef ATH_DEBUG_ALQ if_ath_alq_tidyup(&sc->sc_alq); #endif + ath_lna_div_detach(sc); ath_btcoex_detach(sc); ath_spectral_detach(sc); ath_dfs_detach(sc); diff --git a/sys/dev/ath/if_ath_debug.h b/sys/dev/ath/if_ath_debug.h index b7b5a783a879..83597afaa1a4 100644 --- a/sys/dev/ath/if_ath_debug.h +++ b/sys/dev/ath/if_ath_debug.h @@ -67,6 +67,7 @@ enum { ATH_DEBUG_EDMA_RX = 0x200000000ULL, /* RX EDMA state */ ATH_DEBUG_SW_TX_FILT = 0x400000000ULL, /* SW TX FF */ ATH_DEBUG_NODE_PWRSAVE = 0x800000000ULL, /* node powersave */ + ATH_DEBUG_DIVERSITY = 0x1000000000ULL, /* Diversity logic */ ATH_DEBUG_ANY = 0xffffffffffffffffULL }; diff --git a/sys/dev/ath/if_ath_lna_div.c b/sys/dev/ath/if_ath_lna_div.c new file mode 100644 index 000000000000..5edafa358d63 --- /dev/null +++ b/sys/dev/ath/if_ath_lna_div.c @@ -0,0 +1,798 @@ +/*- + * Copyright (c) 2013 Adrian Chadd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ +#include +__FBSDID("$FreeBSD$"); + +/* + * This module handles LNA diversity for those chips which implement LNA + * mixing (AR9285/AR9485.) + */ +#include "opt_ath.h" +#include "opt_inet.h" +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include /* XXX for ether_sprintf */ + +#include + +#include + +#ifdef INET +#include +#include +#endif + +#include +#include +#include + +/* Linux compability macros */ +/* + * XXX these don't handle rounding, underflow, overflow, wrapping! + */ +#define msecs_to_jiffies(a) ( (a) * hz / 1000 ) + +/* + * Methods which are required + */ + +/* + * Attach the LNA diversity to the given interface + */ +int +ath_lna_div_attach(struct ath_softc *sc) +{ + struct if_ath_ant_comb_state *ss; + + /* Only do this if diversity is enabled */ + if (! ath_hal_hasdivantcomb(sc->sc_ah)) + return (0); + + ss = malloc(sizeof(struct if_ath_ant_comb_state), + M_TEMP, M_WAITOK | M_ZERO); + if (ss == NULL) { + device_printf(sc->sc_dev, "%s: failed to allocate\n", + __func__); + /* Don't fail at this point */ + return (0); + } + + /* Let's flip this on */ + sc->sc_lna_div = ss; + sc->sc_dolnadiv = 1; + + return (0); +} + +/* + * Detach the LNA diversity state from the given interface + */ +int +ath_lna_div_detach(struct ath_softc *sc) +{ + if (sc->sc_lna_div != NULL) { + free(sc->sc_lna_div, M_TEMP); + sc->sc_lna_div = NULL; + } + sc->sc_dolnadiv = 0; + return (0); +} + +/* + * Enable LNA diversity on the current channel if it's required. + */ +int +ath_lna_div_enable(struct ath_softc *sc, const struct ieee80211_channel *chan) +{ + + return (0); +} + +/* + * Handle ioctl requests from the diagnostic interface. + * + * The initial part of this code resembles ath_ioctl_diag(); + * it's likely a good idea to reduce duplication between + * these two routines. + */ +int +ath_lna_div_ioctl(struct ath_softc *sc, struct ath_diag *ad) +{ + unsigned int id = ad->ad_id & ATH_DIAG_ID; + void *indata = NULL; + void *outdata = NULL; + u_int32_t insize = ad->ad_in_size; + u_int32_t outsize = ad->ad_out_size; + int error = 0; +// int val; + + if (ad->ad_id & ATH_DIAG_IN) { + /* + * Copy in data. + */ + indata = malloc(insize, M_TEMP, M_NOWAIT); + if (indata == NULL) { + error = ENOMEM; + goto bad; + } + error = copyin(ad->ad_in_data, indata, insize); + if (error) + goto bad; + } + if (ad->ad_id & ATH_DIAG_DYN) { + /* + * Allocate a buffer for the results (otherwise the HAL + * returns a pointer to a buffer where we can read the + * results). Note that we depend on the HAL leaving this + * pointer for us to use below in reclaiming the buffer; + * may want to be more defensive. + */ + outdata = malloc(outsize, M_TEMP, M_NOWAIT); + if (outdata == NULL) { + error = ENOMEM; + goto bad; + } + } + switch (id) { + default: + error = EINVAL; + } + if (outsize < ad->ad_out_size) + ad->ad_out_size = outsize; + if (outdata && copyout(outdata, ad->ad_out_data, ad->ad_out_size)) + error = EFAULT; +bad: + if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL) + free(indata, M_TEMP); + if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL) + free(outdata, M_TEMP); + return (error); +} + +static HAL_BOOL +ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta, int mindelta, + int main_rssi_avg, int alt_rssi_avg, int pkt_count) +{ + return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) && + (alt_rssi_avg > main_rssi_avg + maxdelta)) || + (alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50); +} + +static void +ath_lnaconf_alt_good_scan(struct if_ath_ant_comb_state *antcomb, + HAL_ANT_COMB_CONFIG *ant_conf, int main_rssi_avg) +{ + antcomb->quick_scan_cnt = 0; + + if (ant_conf->main_lna_conf == HAL_ANT_DIV_COMB_LNA2) + antcomb->rssi_lna2 = main_rssi_avg; + else if (ant_conf->main_lna_conf == HAL_ANT_DIV_COMB_LNA1) + antcomb->rssi_lna1 = main_rssi_avg; + + switch ((ant_conf->main_lna_conf << 4) | ant_conf->alt_lna_conf) { + case (0x10): /* LNA2 A-B */ + antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; + antcomb->first_quick_scan_conf = + HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; + antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA1; + break; + case (0x20): /* LNA1 A-B */ + antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; + antcomb->first_quick_scan_conf = + HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; + antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA2; + break; + case (0x21): /* LNA1 LNA2 */ + antcomb->main_conf = HAL_ANT_DIV_COMB_LNA2; + antcomb->first_quick_scan_conf = + HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; + antcomb->second_quick_scan_conf = + HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; + break; + case (0x12): /* LNA2 LNA1 */ + antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1; + antcomb->first_quick_scan_conf = + HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; + antcomb->second_quick_scan_conf = + HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; + break; + case (0x13): /* LNA2 A+B */ + antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; + antcomb->first_quick_scan_conf = + HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; + antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA1; + break; + case (0x23): /* LNA1 A+B */ + antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; + antcomb->first_quick_scan_conf = + HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; + antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA2; + break; + default: + break; + } +} + +static void +ath_select_ant_div_from_quick_scan(struct if_ath_ant_comb_state *antcomb, + HAL_ANT_COMB_CONFIG *div_ant_conf, int main_rssi_avg, + int alt_rssi_avg, int alt_ratio) +{ + /* alt_good */ + switch (antcomb->quick_scan_cnt) { + case 0: + /* set alt to main, and alt to first conf */ + div_ant_conf->main_lna_conf = antcomb->main_conf; + div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf; + break; + case 1: + /* set alt to main, and alt to first conf */ + div_ant_conf->main_lna_conf = antcomb->main_conf; + div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf; + antcomb->rssi_first = main_rssi_avg; + antcomb->rssi_second = alt_rssi_avg; + + if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) { + /* main is LNA1 */ + if (ath_is_alt_ant_ratio_better(alt_ratio, + ATH_ANT_DIV_COMB_LNA1_DELTA_HI, + ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, + main_rssi_avg, alt_rssi_avg, + antcomb->total_pkt_count)) + antcomb->first_ratio = AH_TRUE; + else + antcomb->first_ratio = AH_FALSE; + } else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2) { + if (ath_is_alt_ant_ratio_better(alt_ratio, + ATH_ANT_DIV_COMB_LNA1_DELTA_MID, + ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, + main_rssi_avg, alt_rssi_avg, + antcomb->total_pkt_count)) + antcomb->first_ratio = AH_TRUE; + else + antcomb->first_ratio = AH_FALSE; + } else { + if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) && + (alt_rssi_avg > main_rssi_avg + + ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) || + (alt_rssi_avg > main_rssi_avg)) && + (antcomb->total_pkt_count > 50)) + antcomb->first_ratio = AH_TRUE; + else + antcomb->first_ratio = AH_FALSE; + } + break; + case 2: + antcomb->alt_good = AH_FALSE; + antcomb->scan_not_start = AH_FALSE; + antcomb->scan = AH_FALSE; + antcomb->rssi_first = main_rssi_avg; + antcomb->rssi_third = alt_rssi_avg; + + if (antcomb->second_quick_scan_conf == HAL_ANT_DIV_COMB_LNA1) + antcomb->rssi_lna1 = alt_rssi_avg; + else if (antcomb->second_quick_scan_conf == + HAL_ANT_DIV_COMB_LNA2) + antcomb->rssi_lna2 = alt_rssi_avg; + else if (antcomb->second_quick_scan_conf == + HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2) { + if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2) + antcomb->rssi_lna2 = main_rssi_avg; + else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) + antcomb->rssi_lna1 = main_rssi_avg; + } + + if (antcomb->rssi_lna2 > antcomb->rssi_lna1 + + ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA) + div_ant_conf->main_lna_conf = HAL_ANT_DIV_COMB_LNA2; + else + div_ant_conf->main_lna_conf = HAL_ANT_DIV_COMB_LNA1; + + if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) { + if (ath_is_alt_ant_ratio_better(alt_ratio, + ATH_ANT_DIV_COMB_LNA1_DELTA_HI, + ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, + main_rssi_avg, alt_rssi_avg, + antcomb->total_pkt_count)) + antcomb->second_ratio = AH_TRUE; + else + antcomb->second_ratio = AH_FALSE; + } else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2) { + if (ath_is_alt_ant_ratio_better(alt_ratio, + ATH_ANT_DIV_COMB_LNA1_DELTA_MID, + ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, + main_rssi_avg, alt_rssi_avg, + antcomb->total_pkt_count)) + antcomb->second_ratio = AH_TRUE; + else + antcomb->second_ratio = AH_FALSE; + } else { + if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) && + (alt_rssi_avg > main_rssi_avg + + ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) || + (alt_rssi_avg > main_rssi_avg)) && + (antcomb->total_pkt_count > 50)) + antcomb->second_ratio = AH_TRUE; + else + antcomb->second_ratio = AH_FALSE; + } + + /* set alt to the conf with maximun ratio */ + if (antcomb->first_ratio && antcomb->second_ratio) { + if (antcomb->rssi_second > antcomb->rssi_third) { + /* first alt*/ + if ((antcomb->first_quick_scan_conf == + HAL_ANT_DIV_COMB_LNA1) || + (antcomb->first_quick_scan_conf == + HAL_ANT_DIV_COMB_LNA2)) + /* Set alt LNA1 or LNA2*/ + if (div_ant_conf->main_lna_conf == + HAL_ANT_DIV_COMB_LNA2) + div_ant_conf->alt_lna_conf = + HAL_ANT_DIV_COMB_LNA1; + else + div_ant_conf->alt_lna_conf = + HAL_ANT_DIV_COMB_LNA2; + else + /* Set alt to A+B or A-B */ + div_ant_conf->alt_lna_conf = + antcomb->first_quick_scan_conf; + } else if ((antcomb->second_quick_scan_conf == + HAL_ANT_DIV_COMB_LNA1) || + (antcomb->second_quick_scan_conf == + HAL_ANT_DIV_COMB_LNA2)) { + /* Set alt LNA1 or LNA2 */ + if (div_ant_conf->main_lna_conf == + HAL_ANT_DIV_COMB_LNA2) + div_ant_conf->alt_lna_conf = + HAL_ANT_DIV_COMB_LNA1; + else + div_ant_conf->alt_lna_conf = + HAL_ANT_DIV_COMB_LNA2; + } else { + /* Set alt to A+B or A-B */ + div_ant_conf->alt_lna_conf = + antcomb->second_quick_scan_conf; + } + } else if (antcomb->first_ratio) { + /* first alt */ + if ((antcomb->first_quick_scan_conf == + HAL_ANT_DIV_COMB_LNA1) || + (antcomb->first_quick_scan_conf == + HAL_ANT_DIV_COMB_LNA2)) + /* Set alt LNA1 or LNA2 */ + if (div_ant_conf->main_lna_conf == + HAL_ANT_DIV_COMB_LNA2) + div_ant_conf->alt_lna_conf = + HAL_ANT_DIV_COMB_LNA1; + else + div_ant_conf->alt_lna_conf = + HAL_ANT_DIV_COMB_LNA2; + else + /* Set alt to A+B or A-B */ + div_ant_conf->alt_lna_conf = + antcomb->first_quick_scan_conf; + } else if (antcomb->second_ratio) { + /* second alt */ + if ((antcomb->second_quick_scan_conf == + HAL_ANT_DIV_COMB_LNA1) || + (antcomb->second_quick_scan_conf == + HAL_ANT_DIV_COMB_LNA2)) + /* Set alt LNA1 or LNA2 */ + if (div_ant_conf->main_lna_conf == + HAL_ANT_DIV_COMB_LNA2) + div_ant_conf->alt_lna_conf = + HAL_ANT_DIV_COMB_LNA1; + else + div_ant_conf->alt_lna_conf = + HAL_ANT_DIV_COMB_LNA2; + else + /* Set alt to A+B or A-B */ + div_ant_conf->alt_lna_conf = + antcomb->second_quick_scan_conf; + } else { + /* main is largest */ + if ((antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) || + (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2)) + /* Set alt LNA1 or LNA2 */ + if (div_ant_conf->main_lna_conf == + HAL_ANT_DIV_COMB_LNA2) + div_ant_conf->alt_lna_conf = + HAL_ANT_DIV_COMB_LNA1; + else + div_ant_conf->alt_lna_conf = + HAL_ANT_DIV_COMB_LNA2; + else + /* Set alt to A+B or A-B */ + div_ant_conf->alt_lna_conf = antcomb->main_conf; + } + break; + default: + break; + } +} + +static void +ath_ant_div_conf_fast_divbias(HAL_ANT_COMB_CONFIG *ant_conf) +{ + /* Adjust the fast_div_bias based on main and alt lna conf */ + switch ((ant_conf->main_lna_conf << 4) | ant_conf->alt_lna_conf) { + case (0x01): /* A-B LNA2 */ + ant_conf->fast_div_bias = 0x3b; + break; + case (0x02): /* A-B LNA1 */ + ant_conf->fast_div_bias = 0x3d; + break; + case (0x03): /* A-B A+B */ + ant_conf->fast_div_bias = 0x1; + break; + case (0x10): /* LNA2 A-B */ + ant_conf->fast_div_bias = 0x7; + break; + case (0x12): /* LNA2 LNA1 */ + ant_conf->fast_div_bias = 0x2; + break; + case (0x13): /* LNA2 A+B */ + ant_conf->fast_div_bias = 0x7; + break; + case (0x20): /* LNA1 A-B */ + ant_conf->fast_div_bias = 0x6; + break; + case (0x21): /* LNA1 LNA2 */ + ant_conf->fast_div_bias = 0x0; + break; + case (0x23): /* LNA1 A+B */ + ant_conf->fast_div_bias = 0x6; + break; + case (0x30): /* A+B A-B */ + ant_conf->fast_div_bias = 0x1; + break; + case (0x31): /* A+B LNA2 */ + ant_conf->fast_div_bias = 0x3b; + break; + case (0x32): /* A+B LNA1 */ + ant_conf->fast_div_bias = 0x3d; + break; + default: + break; + } +} + +/* Antenna diversity and combining */ +void +ath_lna_rx_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs, + unsigned long ticks, int hz) +{ + HAL_ANT_COMB_CONFIG div_ant_conf; + struct if_ath_ant_comb_state *antcomb = sc->sc_lna_div; + int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set; + int curr_main_set, curr_bias; + int main_rssi = rs->rs_rssi_ctl[0]; + int alt_rssi = rs->rs_rssi_ctl[1]; + int rx_ant_conf, main_ant_conf, alt_ant_conf; + HAL_BOOL short_scan = AH_FALSE; + + rx_ant_conf = (rs->rs_rssi_ctl[2] >> 4) & ATH_ANT_RX_MASK; + main_ant_conf = (rs->rs_rssi_ctl[2] >> 2) & ATH_ANT_RX_MASK; + alt_ant_conf = (rs->rs_rssi_ctl[2] >> 0) & ATH_ANT_RX_MASK; + +#if 0 + DPRINTF(sc, ATH_DEBUG_DIVERSITY, + "%s: RSSI %d/%d, conf %x/%x, rxconf %x, LNA: %d; ANT: %d; " + "FastDiv: %d\n", + __func__, + main_rssi, + alt_rssi, + main_ant_conf, + alt_ant_conf, + rx_ant_conf, + !!(rs->rs_rssi_ctl[2] & 0x80), + !!(rs->rs_rssi_ctl[2] & 0x40), + !!(rs->rs_rssi_ext[2] & 0x40)); +#endif + + /* + * If LNA diversity combining isn't enabled, don't run this. + */ + if (! sc->sc_dolnadiv) + return; + + /* + * XXX this is ugly, but the HAL code attaches the + * LNA diversity to the TX antenna settings. + * I don't know why. + */ + if (sc->sc_txantenna != HAL_ANT_VARIABLE) + return; + + /* Record packet only when alt_rssi is positive */ + if (main_rssi > 0 && alt_rssi > 0) { + antcomb->total_pkt_count++; + antcomb->main_total_rssi += main_rssi; + antcomb->alt_total_rssi += alt_rssi; + if (main_ant_conf == rx_ant_conf) + antcomb->main_recv_cnt++; + else + antcomb->alt_recv_cnt++; + } + + /* Short scan check */ + if (antcomb->scan && antcomb->alt_good) { + if (time_after(ticks, antcomb->scan_start_time + + msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR))) + short_scan = AH_TRUE; + else + if (antcomb->total_pkt_count == + ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) { + alt_ratio = ((antcomb->alt_recv_cnt * 100) / + antcomb->total_pkt_count); + if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO) + short_scan = AH_TRUE; + } + } + + if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) || + rs->rs_moreaggr) && !short_scan) + return; + + if (antcomb->total_pkt_count) { + alt_ratio = ((antcomb->alt_recv_cnt * 100) / + antcomb->total_pkt_count); + main_rssi_avg = (antcomb->main_total_rssi / + antcomb->total_pkt_count); + alt_rssi_avg = (antcomb->alt_total_rssi / + antcomb->total_pkt_count); + } + + OS_MEMZERO(&div_ant_conf, sizeof(div_ant_conf)); + + ath_hal_div_comb_conf_get(sc->sc_ah, &div_ant_conf); + curr_alt_set = div_ant_conf.alt_lna_conf; + curr_main_set = div_ant_conf.main_lna_conf; + curr_bias = div_ant_conf.fast_div_bias; + + antcomb->count++; + + if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) { + if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) { + ath_lnaconf_alt_good_scan(antcomb, &div_ant_conf, + main_rssi_avg); + antcomb->alt_good = AH_TRUE; + } else { + antcomb->alt_good = AH_FALSE; + } + + antcomb->count = 0; + antcomb->scan = AH_TRUE; + antcomb->scan_not_start = AH_TRUE; + } + + if (!antcomb->scan) { + if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) { + if (curr_alt_set == HAL_ANT_DIV_COMB_LNA2) { + /* Switch main and alt LNA */ + div_ant_conf.main_lna_conf = + HAL_ANT_DIV_COMB_LNA2; + div_ant_conf.alt_lna_conf = + HAL_ANT_DIV_COMB_LNA1; + } else if (curr_alt_set == HAL_ANT_DIV_COMB_LNA1) { + div_ant_conf.main_lna_conf = + HAL_ANT_DIV_COMB_LNA1; + div_ant_conf.alt_lna_conf = + HAL_ANT_DIV_COMB_LNA2; + } + + goto div_comb_done; + } else if ((curr_alt_set != HAL_ANT_DIV_COMB_LNA1) && + (curr_alt_set != HAL_ANT_DIV_COMB_LNA2)) { + /* Set alt to another LNA */ + if (curr_main_set == HAL_ANT_DIV_COMB_LNA2) + div_ant_conf.alt_lna_conf = + HAL_ANT_DIV_COMB_LNA1; + else if (curr_main_set == HAL_ANT_DIV_COMB_LNA1) + div_ant_conf.alt_lna_conf = + HAL_ANT_DIV_COMB_LNA2; + + goto div_comb_done; + } + + if ((alt_rssi_avg < (main_rssi_avg + + ATH_ANT_DIV_COMB_LNA1_LNA2_DELTA))) + goto div_comb_done; + } + + if (!antcomb->scan_not_start) { + switch (curr_alt_set) { + case HAL_ANT_DIV_COMB_LNA2: + antcomb->rssi_lna2 = alt_rssi_avg; + antcomb->rssi_lna1 = main_rssi_avg; + antcomb->scan = AH_TRUE; + /* set to A+B */ + div_ant_conf.main_lna_conf = + HAL_ANT_DIV_COMB_LNA1; + div_ant_conf.alt_lna_conf = + HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; + break; + case HAL_ANT_DIV_COMB_LNA1: + antcomb->rssi_lna1 = alt_rssi_avg; + antcomb->rssi_lna2 = main_rssi_avg; + antcomb->scan = AH_TRUE; + /* set to A+B */ + div_ant_conf.main_lna_conf = HAL_ANT_DIV_COMB_LNA2; + div_ant_conf.alt_lna_conf = + HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; + break; + case HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2: + antcomb->rssi_add = alt_rssi_avg; + antcomb->scan = AH_TRUE; + /* set to A-B */ + div_ant_conf.alt_lna_conf = + HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; + break; + case HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2: + antcomb->rssi_sub = alt_rssi_avg; + antcomb->scan = AH_FALSE; + if (antcomb->rssi_lna2 > + (antcomb->rssi_lna1 + + ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) { + /* use LNA2 as main LNA */ + if ((antcomb->rssi_add > antcomb->rssi_lna1) && + (antcomb->rssi_add > antcomb->rssi_sub)) { + /* set to A+B */ + div_ant_conf.main_lna_conf = + HAL_ANT_DIV_COMB_LNA2; + div_ant_conf.alt_lna_conf = + HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; + } else if (antcomb->rssi_sub > + antcomb->rssi_lna1) { + /* set to A-B */ + div_ant_conf.main_lna_conf = + HAL_ANT_DIV_COMB_LNA2; + div_ant_conf.alt_lna_conf = + HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; + } else { + /* set to LNA1 */ + div_ant_conf.main_lna_conf = + HAL_ANT_DIV_COMB_LNA2; + div_ant_conf.alt_lna_conf = + HAL_ANT_DIV_COMB_LNA1; + } + } else { + /* use LNA1 as main LNA */ + if ((antcomb->rssi_add > antcomb->rssi_lna2) && + (antcomb->rssi_add > antcomb->rssi_sub)) { + /* set to A+B */ + div_ant_conf.main_lna_conf = + HAL_ANT_DIV_COMB_LNA1; + div_ant_conf.alt_lna_conf = + HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; + } else if (antcomb->rssi_sub > + antcomb->rssi_lna1) { + /* set to A-B */ + div_ant_conf.main_lna_conf = + HAL_ANT_DIV_COMB_LNA1; + div_ant_conf.alt_lna_conf = + HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; + } else { + /* set to LNA2 */ + div_ant_conf.main_lna_conf = + HAL_ANT_DIV_COMB_LNA1; + div_ant_conf.alt_lna_conf = + HAL_ANT_DIV_COMB_LNA2; + } + } + break; + default: + break; + } + } else { + if (!antcomb->alt_good) { + antcomb->scan_not_start = AH_FALSE; + /* Set alt to another LNA */ + if (curr_main_set == HAL_ANT_DIV_COMB_LNA2) { + div_ant_conf.main_lna_conf = + HAL_ANT_DIV_COMB_LNA2; + div_ant_conf.alt_lna_conf = + HAL_ANT_DIV_COMB_LNA1; + } else if (curr_main_set == HAL_ANT_DIV_COMB_LNA1) { + div_ant_conf.main_lna_conf = + HAL_ANT_DIV_COMB_LNA1; + div_ant_conf.alt_lna_conf = + HAL_ANT_DIV_COMB_LNA2; + } + goto div_comb_done; + } + } + + ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf, + main_rssi_avg, alt_rssi_avg, + alt_ratio); + + antcomb->quick_scan_cnt++; + +div_comb_done: + ath_ant_div_conf_fast_divbias(&div_ant_conf); + + ath_hal_div_comb_conf_set(sc->sc_ah, &div_ant_conf); + + DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: total_pkt_count=%d\n", + __func__, antcomb->total_pkt_count); + + DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_total_rssi=%d\n", + __func__, antcomb->main_total_rssi); + DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: alt_total_rssi=%d\n", + __func__, antcomb->alt_total_rssi); + + DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_rssi_avg=%d\n", + __func__, main_rssi_avg); + DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: alt_alt_rssi_avg=%d\n", + __func__, alt_rssi_avg); + + DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_recv_cnt=%d\n", + __func__, antcomb->main_recv_cnt); + DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: alt_recv_cnt=%d\n", + __func__, antcomb->alt_recv_cnt); + +// if (curr_alt_set != div_ant_conf.alt_lna_conf) + DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: lna_conf: %x -> %x\n", + __func__, curr_alt_set, div_ant_conf.alt_lna_conf); +// if (curr_main_set != div_ant_conf.main_lna_conf) + DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_lna_conf: %x -> %x\n", + __func__, curr_main_set, div_ant_conf.main_lna_conf); +// if (curr_bias != div_ant_conf.fast_div_bias) + DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: fast_div_bias: %x -> %x\n", + __func__, curr_bias, div_ant_conf.fast_div_bias); + + antcomb->scan_start_time = ticks; + antcomb->total_pkt_count = 0; + antcomb->main_total_rssi = 0; + antcomb->alt_total_rssi = 0; + antcomb->main_recv_cnt = 0; + antcomb->alt_recv_cnt = 0; +} + diff --git a/sys/dev/ath/if_ath_lna_div.h b/sys/dev/ath/if_ath_lna_div.h new file mode 100644 index 000000000000..f8025a140f3e --- /dev/null +++ b/sys/dev/ath/if_ath_lna_div.h @@ -0,0 +1,89 @@ +/*- + * Copyright (c) 2013 Adrian Chadd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ +#ifndef __IF_ATH_LNA_DIV_H__ +#define __IF_ATH_LNA_DIV_H__ + +#define ATH_ANT_RX_CURRENT_SHIFT 4 +#define ATH_ANT_RX_MAIN_SHIFT 2 +#define ATH_ANT_RX_MASK 0x3 + +#define ATH_ANT_DIV_COMB_SHORT_SCAN_INTR 50 +#define ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT 0x100 +#define ATH_ANT_DIV_COMB_MAX_PKTCOUNT 0x200 +#define ATH_ANT_DIV_COMB_INIT_COUNT 95 +#define ATH_ANT_DIV_COMB_MAX_COUNT 100 +#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO 30 +#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO2 20 + +#define ATH_ANT_DIV_COMB_LNA1_LNA2_DELTA -3 +#define ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA -1 +#define ATH_ANT_DIV_COMB_LNA1_DELTA_HI -4 +#define ATH_ANT_DIV_COMB_LNA1_DELTA_MID -2 +#define ATH_ANT_DIV_COMB_LNA1_DELTA_LOW 2 + +struct if_ath_ant_comb_state { + uint16_t count; + uint16_t total_pkt_count; + HAL_BOOL scan; + HAL_BOOL scan_not_start; + int main_total_rssi; + int alt_total_rssi; + int alt_recv_cnt; + int main_recv_cnt; + int rssi_lna1; + int rssi_lna2; + int rssi_add; + int rssi_sub; + int rssi_first; + int rssi_second; + int rssi_third; + HAL_BOOL alt_good; + int quick_scan_cnt; + int main_conf; + HAL_ANT_DIV_COMB_LNA_CONF first_quick_scan_conf; + HAL_ANT_DIV_COMB_LNA_CONF second_quick_scan_conf; + int first_bias; + int second_bias; + HAL_BOOL first_ratio; + HAL_BOOL second_ratio; + unsigned long scan_start_time; +}; + +extern int ath_lna_div_attach(struct ath_softc *sc); +extern int ath_lna_div_detach(struct ath_softc *sc); +extern int ath_lna_div_ioctl(struct ath_softc *sc, struct ath_diag *ad); +extern int ath_lna_div_enable(struct ath_softc *sc, + const struct ieee80211_channel *ch); + +extern void ath_lna_rx_comb_scan(struct ath_softc *sc, + struct ath_rx_status *rs, unsigned long ticks, int hz); + +#endif /* __IF_ATH_LNA_DIV_H__ */ diff --git a/sys/dev/ath/if_ath_rx.c b/sys/dev/ath/if_ath_rx.c index efe5a2bf176e..d9e212bf2aca 100644 --- a/sys/dev/ath/if_ath_rx.c +++ b/sys/dev/ath/if_ath_rx.c @@ -119,6 +119,8 @@ __FBSDID("$FreeBSD$"); #include #endif +#include + /* * Calculate the receive filter according to the * operating mode and state: @@ -516,7 +518,6 @@ ath_rx_pkt(struct ath_softc *sc, struct ath_rx_status *rs, HAL_STATUS status, uint64_t tsf, int nf, HAL_RX_QUEUE qtype, struct ath_buf *bf, struct mbuf *m) { - struct ath_hal *ah = sc->sc_ah; uint64_t rstamp; int len, type; struct ifnet *ifp = sc->sc_ifp; @@ -843,10 +844,10 @@ ath_rx_pkt(struct ath_softc *sc, struct ath_rx_status *rs, HAL_STATUS status, sc->sc_rxotherant = 0; } - /* Newer school diversity - kite specific for now */ - /* XXX perhaps migrate the normal diversity code to this? */ - if ((ah)->ah_rxAntCombDiversity) - (*(ah)->ah_rxAntCombDiversity)(ah, rs, ticks, hz); + /* Handle slow diversity if enabled */ + if (sc->sc_dolnadiv) { + ath_lna_rx_comb_scan(sc, rs, ticks, hz); + } if (sc->sc_softled) { /* diff --git a/sys/dev/ath/if_athvar.h b/sys/dev/ath/if_athvar.h index 7a943d932100..6b074d6c95c5 100644 --- a/sys/dev/ath/if_athvar.h +++ b/sys/dev/ath/if_athvar.h @@ -630,6 +630,7 @@ struct ath_softc { sc_rx_stbc : 1, sc_tx_stbc : 1, sc_hasenforcetxop : 1, /* support enforce TxOP */ + sc_hasdivcomb : 1, /* RX diversity combining */ sc_rx_lnamixer : 1; /* RX using LNA mixing */ int sc_cabq_enable; /* Enable cabq transmission */ @@ -841,6 +842,10 @@ struct ath_softc { void *sc_spectral; int sc_dospectral; + /* LNA diversity related state */ + void *sc_lna_div; + int sc_dolnadiv; + /* ALQ */ #ifdef ATH_DEBUG_ALQ struct if_ath_alq sc_alq; @@ -1272,6 +1277,9 @@ void ath_intr(void *); #define ath_hal_hasrxlnamixer(_ah) \ (ath_hal_getcapability(_ah, HAL_CAP_RX_LNA_MIXING, 0, NULL) == HAL_OK) +#define ath_hal_hasdivantcomb(_ah) \ + (ath_hal_getcapability(_ah, HAL_CAP_ANT_DIV_COMB, 0, NULL) == HAL_OK) + /* EDMA definitions */ #define ath_hal_hasedma(_ah) \ (ath_hal_getcapability(_ah, HAL_CAP_ENHANCED_DMA_SUPPORT, \ @@ -1458,4 +1466,9 @@ void ath_intr(void *); #define ath_hal_btcoex_disable(_ah) \ ((*(_ah)->ah_btCoexDisable)((_ah))) +#define ath_hal_div_comb_conf_get(_ah, _conf) \ + ((*(_ah)->ah_divLnaConfGet)((_ah), (_conf))) +#define ath_hal_div_comb_conf_set(_ah, _conf) \ + ((*(_ah)->ah_divLnaConfSet)((_ah), (_conf))) + #endif /* _DEV_ATH_ATHVAR_H */ diff --git a/sys/modules/ath/Makefile b/sys/modules/ath/Makefile index 1ae849f2a717..7198a53abea9 100644 --- a/sys/modules/ath/Makefile +++ b/sys/modules/ath/Makefile @@ -38,7 +38,7 @@ KMOD= if_ath SRCS= if_ath.c if_ath_alq.c if_ath_debug.c if_ath_keycache.c if_ath_sysctl.c SRCS+= if_ath_tx.c if_ath_tx_ht.c if_ath_led.c if_ath_rx.c if_ath_tdma.c SRCS+= if_ath_beacon.c if_ath_rx_edma.c if_ath_tx_edma.c if_ath_spectral.c -SRCS+= if_ath_btcoex.c +SRCS+= if_ath_btcoex.c if_ath_lna_div.c # NB: v3 eeprom support used by both AR5211 and AR5212; just include it SRCS+= ah_osdep.c ah.c ah_regdomain.c ah_eeprom_v3.c SRCS+= device_if.h bus_if.h pci_if.h opt_inet.h opt_ath.h opt_ah.h opt_wlan.h