-Index: madwifi-trunk-r3314/ath/if_ath.c
-===================================================================
---- madwifi-trunk-r3314.orig/ath/if_ath.c 2008-06-01 20:07:35.000000000 +0200
-+++ madwifi-trunk-r3314/ath/if_ath.c 2008-06-01 20:17:01.000000000 +0200
-@@ -2528,7 +2528,7 @@
+--- 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)
++ 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);