--- a/ath/if_ath.c +++ b/ath/if_ath.c @@ -383,6 +383,8 @@ static void ath_poll_disable(struct net_ static void ath_poll_enable(struct net_device *dev); static void ath_fetch_idle_time(struct ath_softc *sc); static void ath_set_timing(struct ath_softc *sc); +static void ath_update_cca_thresh(struct ath_softc *sc); +static int ath_hw_read_nf(struct ath_softc *sc); /* calibrate every 30 secs in steady state but check every second at first. */ static int ath_calinterval = ATH_SHORT_CALINTERVAL; @@ -2623,6 +2625,10 @@ ath_init(struct net_device *dev) goto done; } + ath_hal_process_noisefloor(ah); + ic->ic_channoise = ath_hal_get_channel_noise(ah, &(sc->sc_curchan)); + ath_update_cca_thresh(sc); + if (sc->sc_softled) ath_hal_gpioCfgOutput(ah, sc->sc_ledpin); @@ -3024,6 +3030,10 @@ ath_reset(struct net_device *dev) EPRINTF(sc, "Unable to reset hardware: '%s' (HAL status %u)\n", ath_get_hal_status_desc(status), status); + ath_hal_process_noisefloor(ah); + ic->ic_channoise = ath_hal_get_channel_noise(ah, &(sc->sc_curchan)); + ath_update_cca_thresh(sc); + ath_setintmit(sc); ath_update_txpow(sc); /* update tx power state */ ath_radar_update(sc); @@ -9374,9 +9384,11 @@ ath_calibrate(unsigned long arg) sc->sc_curchan.channel); sc->sc_stats.ast_per_calfail++; } - ic->ic_channoise = ath_hal_get_channel_noise(ah, &(sc->sc_curchan)); ath_hal_process_noisefloor(ah); + ic->ic_channoise = ath_hal_get_channel_noise(ah, &(sc->sc_curchan)); + ath_update_cca_thresh(sc); + if (isIQdone == AH_TRUE) { /* Unless user has overridden calibration interval, * upgrade to less frequent calibration */ @@ -9711,8 +9723,6 @@ ath_newstate(struct ieee80211vap *vap, e break; } - ath_hal_process_noisefloor(ah); - ic->ic_channoise = ath_hal_get_channel_noise(ah, &(sc->sc_curchan)); /* * Reset rssi stats; maybe not the best place... */ @@ -10968,6 +10978,7 @@ enum { ATH_INTMIT, ATH_NOISE_IMMUNITY, ATH_OFDM_WEAK_DET, + ATH_CCA_THRESH, ATH_CHANBW, ATH_OUTDOOR, ATH_DISTANCE, @@ -11110,6 +11121,66 @@ ath_sysctl_get_intmit(struct ath_softc * return 0; } +#define AR_PHY_CCA 0x9864 +#define AR_PHY_MINCCA_PWR 0x0FF80000 +#define AR_PHY_MINCCA_PWR_S 19 +#define AR_PHY_CCA_THRESH62 0x0007F000 +#define AR_PHY_CCA_THRESH62_S 12 + +static int +ath_nf_from_cca(u32 phy_cca) +{ + int nf = (phy_cca >> 19) & 0x1ff; + nf = -((nf ^ 0x1ff) + 1); + return nf; +} + +static int +ath_hw_read_nf(struct ath_softc *sc) +{ + return ath_nf_from_cca(OS_REG_READ(sc->sc_ah, AR_PHY_CCA)); +} + +static void +ath_update_cca_thresh(struct ath_softc *sc) +{ + struct ath_hal *ah = sc->sc_ah; + int newthr = 0; + u32 phy_cca; + int nf; + + phy_cca = OS_REG_READ(ah, AR_PHY_CCA); + if (sc->sc_cca_thresh < 0) { + newthr = sc->sc_cca_thresh - ath_nf_from_cca(phy_cca); + + /* 0xf is a typical eeprom value for thresh62, + * use it as minimum for signal based thresholds + * to prevent complete connection drops */ + if (newthr < 0xf) + newthr = 0xf; + } else { + newthr = sc->sc_cca_thresh; + } + + if ((newthr < 4) || (newthr >= 127)) + return; + + phy_cca &= ~AR_PHY_CCA_THRESH62; + phy_cca |= newthr << AR_PHY_CCA_THRESH62_S; + OS_REG_WRITE(ah, AR_PHY_CCA, phy_cca); +} + +static int +ath_get_cca_thresh(struct ath_softc *sc) +{ + struct ath_hal *ah = sc->sc_ah; + u32 phy_cca; + + phy_cca = OS_REG_READ(ah, AR_PHY_CCA); + return ath_nf_from_cca(phy_cca) + + ((phy_cca & AR_PHY_CCA_THRESH62) >> AR_PHY_CCA_THRESH62_S); +} + static int ATH_SYSCTL_DECL(ath_sysctl_hwinfo, ctl, write, filp, buffer, lenp, ppos) { @@ -11356,6 +11427,10 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl case ATH_OFDM_WEAK_DET: ret = ath_sysctl_set_intmit(sc, (long)ctl->extra2, val); break; + case ATH_CCA_THRESH: + sc->sc_cca_thresh = val; + ath_update_cca_thresh(sc); + break; default: ret = -EINVAL; break; @@ -11436,6 +11511,9 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl case ATH_OFDM_WEAK_DET: ret = ath_sysctl_get_intmit(sc, (long)ctl->extra2, &val); break; + case ATH_CCA_THRESH: + val = ath_get_cca_thresh(sc); + break; default: ret = -EINVAL; break; @@ -11667,6 +11745,12 @@ static const ctl_table ath_sysctl_templa .proc_handler = ath_sysctl_halparam, .extra2 = (void *)ATH_OFDM_WEAK_DET, }, + { .ctl_name = CTL_AUTO, + .procname = "cca_thresh", + .mode = 0644, + .proc_handler = ath_sysctl_halparam, + .extra2 = (void *)ATH_CCA_THRESH, + }, { 0 } }; --- a/ath/if_athvar.h +++ b/ath/if_athvar.h @@ -844,6 +844,7 @@ struct ath_softc { int sc_cal_interval; /* current calibration interval */ struct timer_list sc_cal_ch; /* calibration timer */ HAL_NODE_STATS sc_halstats; /* station-mode rssi stats */ + int sc_cca_thresh; /* configured CCA threshold */ struct ctl_table_header *sc_sysctl_header; struct ctl_table *sc_sysctls; --- a/ath/ath_wprobe.c +++ b/ath/ath_wprobe.c @@ -133,8 +133,7 @@ ath_wprobe_sync(struct wprobe_iface *dev rx = READ_CLR(ah, AR5K_RXFC); tx = READ_CLR(ah, AR5K_TXFC); OS_REG_WRITE(ah, AR5K_MIBC, 0); - noise = ath_hal_get_channel_noise(sc->sc_ah, &(sc->sc_curchan)); - ic->ic_channoise = noise; + noise = ath_hw_read_nf(sc); WPROBE_FILL_BEGIN(val, ath_wprobe_globals); if (cc & 0xf0000000) {