--- a/ath/if_ath.c +++ b/ath/if_ath.c @@ -1014,9 +1014,7 @@ ath_attach(u_int16_t devid, struct net_d */ sc->sc_hasveol = ath_hal_hasveol(ah); - /* Interference mitigation/ambient noise immunity (ANI). - * In modes other than HAL_M_STA, it causes receive sensitivity - * problems for OFDM. */ + /* Interference mitigation/ambient noise immunity (ANI). */ sc->sc_hasintmit = ath_hal_hasintmit(ah); /* get mac address from hardware */ @@ -1144,6 +1142,11 @@ ath_attach(u_int16_t devid, struct net_d sc->sc_rp_lasttsf = 0; sc->sc_last_tsf = 0; + /* set all 3 to auto */ + sc->sc_intmit = -1; + sc->sc_noise_immunity = -1; + sc->sc_ofdm_weak_det = -1; + return 0; bad3: ieee80211_ifdetach(ic); @@ -2428,6 +2431,43 @@ ath_chan2flags(struct ieee80211_channel return flags; } +static int ath_setintmit(struct ath_softc *sc) +{ + struct ath_hal *ah = sc->sc_ah; + int ret; + int val; + + if (!sc->sc_hasintmit) + return 0; + + switch(sc->sc_intmit) { + case -1: + if (sc->sc_opmode != IEEE80211_M_MONITOR) + val = 1; + else + val = 0; + break; + case 0: /* disabled */ + case 1: /* enabled */ + val = sc->sc_intmit; + break; + default: + return 0; + } + ret = ath_hal_setintmit(ah, val); + if (val) + goto done; + + /* manual settings */ + if ((sc->sc_noise_immunity >= 0) && (sc->sc_noise_immunity <= 5)) + ath_hal_setcapability(ah, HAL_CAP_INTMIT, 2, sc->sc_noise_immunity, NULL); + if ((sc->sc_ofdm_weak_det == 0) || (sc->sc_ofdm_weak_det == 1)) + ath_hal_setcapability(ah, HAL_CAP_INTMIT, 3, sc->sc_ofdm_weak_det, NULL); + +done: + return ret; +} + /* * Context: process context */ @@ -2493,8 +2533,7 @@ ath_init(struct net_device *dev) if (sc->sc_softled) ath_hal_gpioCfgOutput(ah, sc->sc_ledpin); - if ((sc->sc_opmode != HAL_M_STA) && sc->sc_hasintmit) - ath_hal_setintmit(ah, 0); + ath_setintmit(sc); /* * This is needed only to setup initial state @@ -2530,7 +2569,7 @@ ath_init(struct net_device *dev) * Enable MIB interrupts when there are hardware phy counters. * Note we only do this (at the moment) for station mode. */ - if (sc->sc_needmib && ic->ic_opmode == IEEE80211_M_STA) + if (sc->sc_needmib && ath_hal_getintmit(ah, NULL)) sc->sc_imask |= HAL_INT_MIB; ath_hal_intrset(ah, sc->sc_imask); @@ -2787,9 +2826,7 @@ ath_reset(struct net_device *dev) EPRINTF(sc, "Unable to reset hardware: '%s' (HAL status %u)\n", ath_get_hal_status_desc(status), status); - if ((sc->sc_opmode != HAL_M_STA) && sc->sc_hasintmit) - ath_hal_setintmit(ah, 0); - + ath_setintmit(sc); ath_update_txpow(sc); /* update tx power state */ ath_radar_update(sc); ath_setdefantenna(sc, sc->sc_defant); @@ -4174,6 +4211,8 @@ ath_calcrxfilter(struct ath_softc *sc) if (sc->sc_nmonvaps > 0) rfilt |= (HAL_RX_FILTER_CONTROL | HAL_RX_FILTER_BEACON | HAL_RX_FILTER_PROBEREQ | HAL_RX_FILTER_PROM); + if (sc->sc_hasintmit && !sc->sc_needmib && ath_hal_getintmit(ah, NULL)) + rfilt |= HAL_RX_FILTER_PHYERR; if (sc->sc_curchan.privFlags & CHANNEL_DFS) rfilt |= (HAL_RX_FILTER_PHYERR | HAL_RX_FILTER_PHYRADAR); return rfilt; @@ -6526,9 +6565,6 @@ process_rx_again: rs->rs_rssi = 0; len = rs->rs_datalen; - /* DMA sync. dies spectacularly if len == 0 */ - if (len == 0) - goto rx_next; if (rs->rs_more) { /* @@ -8876,9 +8912,7 @@ ath_chan_set(struct ath_softc *sc, struc if (sc->sc_softled) ath_hal_gpioCfgOutput(ah, sc->sc_ledpin); - if ((sc->sc_opmode != HAL_M_STA) && sc->sc_hasintmit) - ath_hal_setintmit(ah, 0); - + ath_setintmit(sc); sc->sc_curchan = hchan; ath_update_txpow(sc); /* update tx power state */ ath_radar_update(sc); @@ -10655,9 +10689,54 @@ enum { ATH_RP_IGNORED = 24, ATH_RADAR_IGNORED = 25, ATH_MAXVAPS = 26, + ATH_INTMIT = 27, + ATH_NOISE_IMMUNITY = 28, + ATH_OFDM_WEAK_DET = 29 }; static int +ath_sysctl_set_intmit(struct ath_softc *sc, long ctl, u_int val) +{ + int ret; + + switch(ctl) { + case ATH_INTMIT: + sc->sc_intmit = val; + break; + case ATH_NOISE_IMMUNITY: + sc->sc_noise_immunity = val; + break; + case ATH_OFDM_WEAK_DET: + sc->sc_ofdm_weak_det = val; + break; + default: + return -EINVAL; + } + ret = ath_setintmit(sc); + ath_calcrxfilter(sc); + return ret; +} + +static int +ath_sysctl_get_intmit(struct ath_softc *sc, long ctl, u_int *val) +{ + struct ath_hal *ah = sc->sc_ah; + + switch(ctl) { + case ATH_INTMIT: + *val = (ath_hal_getcapability(ah, HAL_CAP_INTMIT, 1, NULL) == HAL_OK); + break; + case ATH_NOISE_IMMUNITY: + return ath_hal_getcapability(ah, HAL_CAP_INTMIT, 2, val); + case ATH_OFDM_WEAK_DET: + return ath_hal_getcapability(ah, HAL_CAP_INTMIT, 3, val); + default: + return -EINVAL; + } + return 0; +} + +static int ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl, write, filp, buffer, lenp, ppos) { struct ath_softc *sc = ctl->extra1; @@ -10843,6 +10922,11 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl case ATH_RADAR_IGNORED: sc->sc_radar_ignored = val; break; + case ATH_INTMIT: + case ATH_NOISE_IMMUNITY: + case ATH_OFDM_WEAK_DET: + ret = ath_sysctl_set_intmit(sc, (long)ctl->extra2, val); + break; default: ret = -EINVAL; break; @@ -10909,6 +10993,11 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl case ATH_RADAR_IGNORED: val = sc->sc_radar_ignored; break; + case ATH_INTMIT: + case ATH_NOISE_IMMUNITY: + case ATH_OFDM_WEAK_DET: + ret = ath_sysctl_get_intmit(sc, (long)ctl->extra2, &val); + break; default: ret = -EINVAL; break; @@ -11086,6 +11175,24 @@ static const ctl_table ath_sysctl_templa .proc_handler = ath_sysctl_halparam, .extra2 = (void *)ATH_RADAR_IGNORED, }, + { .ctl_name = CTL_AUTO, + .procname = "intmit", + .mode = 0644, + .proc_handler = ath_sysctl_halparam, + .extra2 = (void *)ATH_INTMIT, + }, + { .ctl_name = CTL_AUTO, + .procname = "noise_immunity", + .mode = 0644, + .proc_handler = ath_sysctl_halparam, + .extra2 = (void *)ATH_NOISE_IMMUNITY, + }, + { .ctl_name = CTL_AUTO, + .procname = "ofdm_weak_det", + .mode = 0644, + .proc_handler = ath_sysctl_halparam, + .extra2 = (void *)ATH_OFDM_WEAK_DET, + }, { 0 } }; --- a/ath/if_athvar.h +++ b/ath/if_athvar.h @@ -693,6 +693,10 @@ struct ath_softc { unsigned int sc_txcont_power; /* Continuous transmit power in 0.5dBm units */ unsigned int sc_txcont_rate; /* Continuous transmit rate in Mbps */ + int8_t sc_intmit; /* Interference mitigation enabled, -1 = auto, based on mode, 0/1 = off/on */ + int8_t sc_noise_immunity; /* Noise immunity level, 0-4, -1 == auto) */ + int8_t sc_ofdm_weak_det; /* OFDM weak frames detection, -1 == auto */ + /* rate tables */ const HAL_RATE_TABLE *sc_rates[IEEE80211_MODE_MAX]; const HAL_RATE_TABLE *sc_currates; /* current rate table */ --- a/ath/if_ath_hal.h +++ b/ath/if_ath_hal.h @@ -67,14 +67,14 @@ static inline HAL_POWER_MODE ath_hal_get static inline HAL_BOOL ath_hal_getdiagstate(struct ath_hal *ah, int request, const void *args, u_int32_t argsize, - void **result, + void *result, u_int32_t *resultsize) { HAL_BOOL ret; ATH_HAL_LOCK_IRQ(ah->ah_sc); ath_hal_set_function(__func__); ret = - ah->ah_getDiagState(ah, request, args, argsize, *result, + ah->ah_getDiagState(ah, request, args, argsize, result, resultsize); ath_hal_set_function(NULL); ATH_HAL_UNLOCK_IRQ(ah->ah_sc);