| 1 | --- a/ath/if_ath.c |
| 2 | +++ b/ath/if_ath.c |
| 3 | @@ -1014,9 +1014,7 @@ ath_attach(u_int16_t devid, struct net_d |
| 4 | */ |
| 5 | sc->sc_hasveol = ath_hal_hasveol(ah); |
| 6 | |
| 7 | - /* Interference mitigation/ambient noise immunity (ANI). |
| 8 | - * In modes other than HAL_M_STA, it causes receive sensitivity |
| 9 | - * problems for OFDM. */ |
| 10 | + /* Interference mitigation/ambient noise immunity (ANI). */ |
| 11 | sc->sc_hasintmit = ath_hal_hasintmit(ah); |
| 12 | |
| 13 | /* get mac address from hardware */ |
| 14 | @@ -1144,6 +1142,11 @@ ath_attach(u_int16_t devid, struct net_d |
| 15 | sc->sc_rp_lasttsf = 0; |
| 16 | sc->sc_last_tsf = 0; |
| 17 | |
| 18 | + /* set all 3 to auto */ |
| 19 | + sc->sc_intmit = -1; |
| 20 | + sc->sc_noise_immunity = -1; |
| 21 | + sc->sc_ofdm_weak_det = -1; |
| 22 | + |
| 23 | return 0; |
| 24 | bad3: |
| 25 | ieee80211_ifdetach(ic); |
| 26 | @@ -2428,6 +2431,43 @@ ath_chan2flags(struct ieee80211_channel |
| 27 | return flags; |
| 28 | } |
| 29 | |
| 30 | +static int ath_setintmit(struct ath_softc *sc) |
| 31 | +{ |
| 32 | + struct ath_hal *ah = sc->sc_ah; |
| 33 | + int ret; |
| 34 | + int val; |
| 35 | + |
| 36 | + if (!sc->sc_hasintmit) |
| 37 | + return 0; |
| 38 | + |
| 39 | + switch(sc->sc_intmit) { |
| 40 | + case -1: |
| 41 | + if (sc->sc_opmode != IEEE80211_M_MONITOR) |
| 42 | + val = 1; |
| 43 | + else |
| 44 | + val = 0; |
| 45 | + break; |
| 46 | + case 0: /* disabled */ |
| 47 | + case 1: /* enabled */ |
| 48 | + val = sc->sc_intmit; |
| 49 | + break; |
| 50 | + default: |
| 51 | + return 0; |
| 52 | + } |
| 53 | + ret = ath_hal_setintmit(ah, val); |
| 54 | + if (val) |
| 55 | + goto done; |
| 56 | + |
| 57 | + /* manual settings */ |
| 58 | + if ((sc->sc_noise_immunity >= 0) && (sc->sc_noise_immunity <= 5)) |
| 59 | + ath_hal_setcapability(ah, HAL_CAP_INTMIT, 2, sc->sc_noise_immunity, NULL); |
| 60 | + if ((sc->sc_ofdm_weak_det == 0) || (sc->sc_ofdm_weak_det == 1)) |
| 61 | + ath_hal_setcapability(ah, HAL_CAP_INTMIT, 3, sc->sc_ofdm_weak_det, NULL); |
| 62 | + |
| 63 | +done: |
| 64 | + return ret; |
| 65 | +} |
| 66 | + |
| 67 | /* |
| 68 | * Context: process context |
| 69 | */ |
| 70 | @@ -2493,8 +2533,7 @@ ath_init(struct net_device *dev) |
| 71 | if (sc->sc_softled) |
| 72 | ath_hal_gpioCfgOutput(ah, sc->sc_ledpin); |
| 73 | |
| 74 | - if ((sc->sc_opmode != HAL_M_STA) && sc->sc_hasintmit) |
| 75 | - ath_hal_setintmit(ah, 0); |
| 76 | + ath_setintmit(sc); |
| 77 | |
| 78 | /* |
| 79 | * This is needed only to setup initial state |
| 80 | @@ -2530,7 +2569,7 @@ ath_init(struct net_device *dev) |
| 81 | * Enable MIB interrupts when there are hardware phy counters. |
| 82 | * Note we only do this (at the moment) for station mode. |
| 83 | */ |
| 84 | - if (sc->sc_needmib && ic->ic_opmode == IEEE80211_M_STA) |
| 85 | + if (sc->sc_needmib && ath_hal_getintmit(ah, NULL)) |
| 86 | sc->sc_imask |= HAL_INT_MIB; |
| 87 | ath_hal_intrset(ah, sc->sc_imask); |
| 88 | |
| 89 | @@ -2787,9 +2826,7 @@ ath_reset(struct net_device *dev) |
| 90 | EPRINTF(sc, "Unable to reset hardware: '%s' (HAL status %u)\n", |
| 91 | ath_get_hal_status_desc(status), status); |
| 92 | |
| 93 | - if ((sc->sc_opmode != HAL_M_STA) && sc->sc_hasintmit) |
| 94 | - ath_hal_setintmit(ah, 0); |
| 95 | - |
| 96 | + ath_setintmit(sc); |
| 97 | ath_update_txpow(sc); /* update tx power state */ |
| 98 | ath_radar_update(sc); |
| 99 | ath_setdefantenna(sc, sc->sc_defant); |
| 100 | @@ -4174,6 +4211,8 @@ ath_calcrxfilter(struct ath_softc *sc) |
| 101 | if (sc->sc_nmonvaps > 0) |
| 102 | rfilt |= (HAL_RX_FILTER_CONTROL | HAL_RX_FILTER_BEACON | |
| 103 | HAL_RX_FILTER_PROBEREQ | HAL_RX_FILTER_PROM); |
| 104 | + if (sc->sc_hasintmit && !sc->sc_needmib && ath_hal_getintmit(ah, NULL)) |
| 105 | + rfilt |= HAL_RX_FILTER_PHYERR; |
| 106 | if (sc->sc_curchan.privFlags & CHANNEL_DFS) |
| 107 | rfilt |= (HAL_RX_FILTER_PHYERR | HAL_RX_FILTER_PHYRADAR); |
| 108 | return rfilt; |
| 109 | @@ -6526,9 +6565,6 @@ process_rx_again: |
| 110 | rs->rs_rssi = 0; |
| 111 | |
| 112 | len = rs->rs_datalen; |
| 113 | - /* DMA sync. dies spectacularly if len == 0 */ |
| 114 | - if (len == 0) |
| 115 | - goto rx_next; |
| 116 | |
| 117 | if (rs->rs_more) { |
| 118 | /* |
| 119 | @@ -8876,9 +8912,7 @@ ath_chan_set(struct ath_softc *sc, struc |
| 120 | if (sc->sc_softled) |
| 121 | ath_hal_gpioCfgOutput(ah, sc->sc_ledpin); |
| 122 | |
| 123 | - if ((sc->sc_opmode != HAL_M_STA) && sc->sc_hasintmit) |
| 124 | - ath_hal_setintmit(ah, 0); |
| 125 | - |
| 126 | + ath_setintmit(sc); |
| 127 | sc->sc_curchan = hchan; |
| 128 | ath_update_txpow(sc); /* update tx power state */ |
| 129 | ath_radar_update(sc); |
| 130 | @@ -10655,9 +10689,54 @@ enum { |
| 131 | ATH_RP_IGNORED = 24, |
| 132 | ATH_RADAR_IGNORED = 25, |
| 133 | ATH_MAXVAPS = 26, |
| 134 | + ATH_INTMIT = 27, |
| 135 | + ATH_NOISE_IMMUNITY = 28, |
| 136 | + ATH_OFDM_WEAK_DET = 29 |
| 137 | }; |
| 138 | |
| 139 | static int |
| 140 | +ath_sysctl_set_intmit(struct ath_softc *sc, long ctl, u_int val) |
| 141 | +{ |
| 142 | + int ret; |
| 143 | + |
| 144 | + switch(ctl) { |
| 145 | + case ATH_INTMIT: |
| 146 | + sc->sc_intmit = val; |
| 147 | + break; |
| 148 | + case ATH_NOISE_IMMUNITY: |
| 149 | + sc->sc_noise_immunity = val; |
| 150 | + break; |
| 151 | + case ATH_OFDM_WEAK_DET: |
| 152 | + sc->sc_ofdm_weak_det = val; |
| 153 | + break; |
| 154 | + default: |
| 155 | + return -EINVAL; |
| 156 | + } |
| 157 | + ret = ath_setintmit(sc); |
| 158 | + ath_calcrxfilter(sc); |
| 159 | + return ret; |
| 160 | +} |
| 161 | + |
| 162 | +static int |
| 163 | +ath_sysctl_get_intmit(struct ath_softc *sc, long ctl, u_int *val) |
| 164 | +{ |
| 165 | + struct ath_hal *ah = sc->sc_ah; |
| 166 | + |
| 167 | + switch(ctl) { |
| 168 | + case ATH_INTMIT: |
| 169 | + *val = (ath_hal_getcapability(ah, HAL_CAP_INTMIT, 1, NULL) == HAL_OK); |
| 170 | + break; |
| 171 | + case ATH_NOISE_IMMUNITY: |
| 172 | + return ath_hal_getcapability(ah, HAL_CAP_INTMIT, 2, val); |
| 173 | + case ATH_OFDM_WEAK_DET: |
| 174 | + return ath_hal_getcapability(ah, HAL_CAP_INTMIT, 3, val); |
| 175 | + default: |
| 176 | + return -EINVAL; |
| 177 | + } |
| 178 | + return 0; |
| 179 | +} |
| 180 | + |
| 181 | +static int |
| 182 | ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl, write, filp, buffer, lenp, ppos) |
| 183 | { |
| 184 | struct ath_softc *sc = ctl->extra1; |
| 185 | @@ -10843,6 +10922,11 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl |
| 186 | case ATH_RADAR_IGNORED: |
| 187 | sc->sc_radar_ignored = val; |
| 188 | break; |
| 189 | + case ATH_INTMIT: |
| 190 | + case ATH_NOISE_IMMUNITY: |
| 191 | + case ATH_OFDM_WEAK_DET: |
| 192 | + ret = ath_sysctl_set_intmit(sc, (long)ctl->extra2, val); |
| 193 | + break; |
| 194 | default: |
| 195 | ret = -EINVAL; |
| 196 | break; |
| 197 | @@ -10909,6 +10993,11 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl |
| 198 | case ATH_RADAR_IGNORED: |
| 199 | val = sc->sc_radar_ignored; |
| 200 | break; |
| 201 | + case ATH_INTMIT: |
| 202 | + case ATH_NOISE_IMMUNITY: |
| 203 | + case ATH_OFDM_WEAK_DET: |
| 204 | + ret = ath_sysctl_get_intmit(sc, (long)ctl->extra2, &val); |
| 205 | + break; |
| 206 | default: |
| 207 | ret = -EINVAL; |
| 208 | break; |
| 209 | @@ -11086,6 +11175,24 @@ static const ctl_table ath_sysctl_templa |
| 210 | .proc_handler = ath_sysctl_halparam, |
| 211 | .extra2 = (void *)ATH_RADAR_IGNORED, |
| 212 | }, |
| 213 | + { .ctl_name = CTL_AUTO, |
| 214 | + .procname = "intmit", |
| 215 | + .mode = 0644, |
| 216 | + .proc_handler = ath_sysctl_halparam, |
| 217 | + .extra2 = (void *)ATH_INTMIT, |
| 218 | + }, |
| 219 | + { .ctl_name = CTL_AUTO, |
| 220 | + .procname = "noise_immunity", |
| 221 | + .mode = 0644, |
| 222 | + .proc_handler = ath_sysctl_halparam, |
| 223 | + .extra2 = (void *)ATH_NOISE_IMMUNITY, |
| 224 | + }, |
| 225 | + { .ctl_name = CTL_AUTO, |
| 226 | + .procname = "ofdm_weak_det", |
| 227 | + .mode = 0644, |
| 228 | + .proc_handler = ath_sysctl_halparam, |
| 229 | + .extra2 = (void *)ATH_OFDM_WEAK_DET, |
| 230 | + }, |
| 231 | { 0 } |
| 232 | }; |
| 233 | |
| 234 | --- a/ath/if_athvar.h |
| 235 | +++ b/ath/if_athvar.h |
| 236 | @@ -693,6 +693,10 @@ struct ath_softc { |
| 237 | unsigned int sc_txcont_power; /* Continuous transmit power in 0.5dBm units */ |
| 238 | unsigned int sc_txcont_rate; /* Continuous transmit rate in Mbps */ |
| 239 | |
| 240 | + int8_t sc_intmit; /* Interference mitigation enabled, -1 = auto, based on mode, 0/1 = off/on */ |
| 241 | + int8_t sc_noise_immunity; /* Noise immunity level, 0-4, -1 == auto) */ |
| 242 | + int8_t sc_ofdm_weak_det; /* OFDM weak frames detection, -1 == auto */ |
| 243 | + |
| 244 | /* rate tables */ |
| 245 | const HAL_RATE_TABLE *sc_rates[IEEE80211_MODE_MAX]; |
| 246 | const HAL_RATE_TABLE *sc_currates; /* current rate table */ |
| 247 | --- a/ath/if_ath_hal.h |
| 248 | +++ b/ath/if_ath_hal.h |
| 249 | @@ -67,14 +67,14 @@ static inline HAL_POWER_MODE ath_hal_get |
| 250 | |
| 251 | static inline HAL_BOOL ath_hal_getdiagstate(struct ath_hal *ah, int request, |
| 252 | const void *args, u_int32_t argsize, |
| 253 | - void **result, |
| 254 | + void *result, |
| 255 | u_int32_t *resultsize) |
| 256 | { |
| 257 | HAL_BOOL ret; |
| 258 | ATH_HAL_LOCK_IRQ(ah->ah_sc); |
| 259 | ath_hal_set_function(__func__); |
| 260 | ret = |
| 261 | - ah->ah_getDiagState(ah, request, args, argsize, *result, |
| 262 | + ah->ah_getDiagState(ah, request, args, argsize, result, |
| 263 | resultsize); |
| 264 | ath_hal_set_function(NULL); |
| 265 | ATH_HAL_UNLOCK_IRQ(ah->ah_sc); |
| 266 | |