summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/ath/if_ath.c129
-rw-r--r--sys/dev/ath/if_athvar.h17
2 files changed, 92 insertions, 54 deletions
diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c
index 4cd1001..8301fbf 100644
--- a/sys/dev/ath/if_ath.c
+++ b/sys/dev/ath/if_ath.c
@@ -219,9 +219,15 @@ static void ath_announce(struct ath_softc *);
SYSCTL_DECL(_hw_ath);
/* XXX validate sysctl values */
-static int ath_calinterval = 30; /* calibrate every 30 secs */
-SYSCTL_INT(_hw_ath, OID_AUTO, calibrate, CTLFLAG_RW, &ath_calinterval,
- 0, "chip calibration interval (secs)");
+static int ath_longcalinterval = 30; /* long cals every 30 secs */
+SYSCTL_INT(_hw_ath, OID_AUTO, longcal, CTLFLAG_RW, &ath_longcalinterval,
+ 0, "long chip calibration interval (secs)");
+static int ath_shortcalinterval = 100; /* short cals every 100 ms */
+SYSCTL_INT(_hw_ath, OID_AUTO, shortcal, CTLFLAG_RW, &ath_shortcalinterval,
+ 0, "short chip calibration interval (msecs)");
+static int ath_resetcalinterval = 20*60; /* reset cal state 20 mins */
+SYSCTL_INT(_hw_ath, OID_AUTO, resetcal, CTLFLAG_RW, &ath_resetcalinterval,
+ 0, "reset chip calibration results (secs)");
static int ath_rxbuf = ATH_RXBUF; /* # rx buffers to allocate */
SYSCTL_INT(_hw_ath, OID_AUTO, rxbuf, CTLFLAG_RW, &ath_rxbuf,
@@ -1433,8 +1439,9 @@ ath_init(void *arg)
* state cached in the driver.
*/
sc->sc_diversity = ath_hal_getdiversity(ah);
- sc->sc_calinterval = 1;
- sc->sc_caltries = 0;
+ sc->sc_lastlongcal = 0;
+ sc->sc_resetcal = 1;
+ sc->sc_lastcalreset = 0;
/*
* Setup the hardware after reset: the key cache
@@ -1566,8 +1573,6 @@ ath_reset(struct ifnet *ifp)
if_printf(ifp, "%s: unable to reset hardware; hal status %u\n",
__func__, status);
sc->sc_diversity = ath_hal_getdiversity(ah);
- sc->sc_calinterval = 1;
- sc->sc_caltries = 0;
if (ath_startrecv(sc) != 0) /* restart recv */
if_printf(ifp, "%s: unable to start recv logic\n", __func__);
/*
@@ -5493,8 +5498,6 @@ ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan)
}
sc->sc_curchan = hchan;
sc->sc_diversity = ath_hal_getdiversity(ah);
- sc->sc_calinterval = 1;
- sc->sc_caltries = 0;
/*
* Re-enable rx framework.
@@ -5528,54 +5531,76 @@ ath_calibrate(void *arg)
{
struct ath_softc *sc = arg;
struct ath_hal *ah = sc->sc_ah;
- HAL_BOOL iqCalDone;
-
- sc->sc_stats.ast_per_cal++;
+ struct ifnet *ifp = sc->sc_ifp;
+ HAL_BOOL longCal, isCalDone;
+ int nextcal;
- if (ath_hal_getrfgain(ah) == HAL_RFGAIN_NEED_CHANGE) {
+ longCal = (ticks - sc->sc_lastlongcal >= ath_longcalinterval*hz);
+ if (longCal) {
+ sc->sc_stats.ast_per_cal++;
+ if (ath_hal_getrfgain(ah) == HAL_RFGAIN_NEED_CHANGE) {
+ /*
+ * Rfgain is out of bounds, reset the chip
+ * to load new gain values.
+ */
+ DPRINTF(sc, ATH_DEBUG_CALIBRATE,
+ "%s: rfgain change\n", __func__);
+ sc->sc_stats.ast_per_rfgain++;
+ ath_reset(ifp);
+ }
/*
- * Rfgain is out of bounds, reset the chip
- * to load new gain values.
+ * If this long cal is after an idle period, then
+ * reset the data collection state so we start fresh.
*/
- DPRINTF(sc, ATH_DEBUG_CALIBRATE,
- "%s: rfgain change\n", __func__);
- sc->sc_stats.ast_per_rfgain++;
- ath_reset(sc->sc_ifp);
+ if (sc->sc_resetcal) {
+ (void) ath_hal_calreset(ah, &sc->sc_curchan);
+ sc->sc_lastcalreset = ticks;
+ sc->sc_resetcal = 0;
+ }
}
- if (!ath_hal_calibrate(ah, &sc->sc_curchan, &iqCalDone)) {
+ if (ath_hal_calibrateN(ah, &sc->sc_curchan, longCal, &isCalDone)) {
+ if (longCal) {
+ /*
+ * Calibrate noise floor data again in case of change.
+ */
+ ath_hal_process_noisefloor(ah);
+ }
+ } else {
DPRINTF(sc, ATH_DEBUG_ANY,
"%s: calibration of channel %u failed\n",
__func__, sc->sc_curchan.channel);
sc->sc_stats.ast_per_calfail++;
}
- /*
- * Calibrate noise floor data again in case of change.
- */
- ath_hal_process_noisefloor(ah);
- /*
- * Poll more frequently when the IQ calibration is in
- * progress to speedup loading the final settings.
- * We temper this aggressive polling with an exponential
- * back off after 4 tries up to ath_calinterval.
- */
- if (iqCalDone || sc->sc_calinterval >= ath_calinterval) {
- sc->sc_caltries = 0;
- sc->sc_calinterval = ath_calinterval;
- } else if (sc->sc_caltries > 4) {
- sc->sc_caltries = 0;
- sc->sc_calinterval <<= 1;
- if (sc->sc_calinterval > ath_calinterval)
- sc->sc_calinterval = ath_calinterval;
- }
- KASSERT(0 < sc->sc_calinterval && sc->sc_calinterval <= ath_calinterval,
- ("bad calibration interval %u", sc->sc_calinterval));
-
- DPRINTF(sc, ATH_DEBUG_CALIBRATE,
- "%s: next +%u (%siqCalDone tries %u)\n", __func__,
- sc->sc_calinterval, iqCalDone ? "" : "!", sc->sc_caltries);
- sc->sc_caltries++;
- callout_reset(&sc->sc_cal_ch, sc->sc_calinterval * hz,
- ath_calibrate, sc);
+ if (!isCalDone) {
+ /*
+ * Use a shorter interval to potentially collect multiple
+ * data samples required to complete calibration. Once
+ * we're told the work is done we drop back to a longer
+ * interval between requests. We're more aggressive doing
+ * work when operating as an AP to improve operation right
+ * after startup.
+ */
+ nextcal = (1000*ath_shortcalinterval)/hz;
+ if (sc->sc_opmode != HAL_M_HOSTAP)
+ nextcal *= 10;
+ } else {
+ nextcal = ath_longcalinterval*hz;
+ sc->sc_lastlongcal = ticks;
+ if (sc->sc_lastcalreset == 0)
+ sc->sc_lastcalreset = sc->sc_lastlongcal;
+ else if (ticks - sc->sc_lastcalreset >= ath_resetcalinterval*hz)
+ sc->sc_resetcal = 1; /* setup reset next trip */
+ }
+
+ if (nextcal != 0) {
+ DPRINTF(sc, ATH_DEBUG_CALIBRATE, "%s: next +%u (%sisCalDone)\n",
+ __func__, nextcal, isCalDone ? "" : "!");
+ callout_reset(&sc->sc_cal_ch, nextcal, ath_calibrate, sc);
+ } else {
+ DPRINTF(sc, ATH_DEBUG_CALIBRATE, "%s: calibration disabled\n",
+ __func__);
+ /* NB: don't rearm timer */
+ }
}
static void
@@ -5803,10 +5828,12 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
* Finally, start any timers and the task q thread
* (in case we didn't go through SCAN state).
*/
- if (sc->sc_calinterval != 0) {
+ if (ath_longcalinterval != 0) {
/* start periodic recalibration timer */
- callout_reset(&sc->sc_cal_ch, sc->sc_calinterval * hz,
- ath_calibrate, sc);
+ callout_reset(&sc->sc_cal_ch, 1, ath_calibrate, sc);
+ } else {
+ DPRINTF(sc, ATH_DEBUG_CALIBRATE,
+ "%s: calibration disabled\n", __func__);
}
taskqueue_unblock(sc->sc_tq);
} else if (nstate == IEEE80211_S_INIT) {
diff --git a/sys/dev/ath/if_athvar.h b/sys/dev/ath/if_athvar.h
index 87ebb5d..0f08eec 100644
--- a/sys/dev/ath/if_athvar.h
+++ b/sys/dev/ath/if_athvar.h
@@ -248,7 +248,8 @@ struct ath_softc {
sc_swbmiss : 1,/* sta mode using sw bmiss */
sc_stagbeacons:1,/* use staggered beacons */
sc_wmetkipmic:1,/* can do WME+TKIP MIC */
- sc_resume_up: 1;/* on resume, start all vaps */
+ sc_resume_up: 1,/* on resume, start all vaps */
+ sc_resetcal : 1;/* reset cal state next trip */
uint32_t sc_eerd; /* regdomain from EEPROM */
uint32_t sc_eecc; /* country code from EEPROM */
/* rate tables */
@@ -334,8 +335,8 @@ struct ath_softc {
int sc_nbcnvaps; /* # vaps with beacons */
struct callout sc_cal_ch; /* callout handle for cals */
- int sc_calinterval; /* current polling interval */
- int sc_caltries; /* cals at current interval */
+ int sc_lastlongcal; /* last long cal completed */
+ int sc_lastcalreset;/* last cal reset done */
HAL_NODE_STATS sc_halstats; /* station-mode rssi stats */
};
@@ -438,6 +439,16 @@ void ath_intr(void *);
((*(_ah)->ah_setChannel)((_ah), (_chan)))
#define ath_hal_calibrate(_ah, _chan, _iqcal) \
((*(_ah)->ah_perCalibration)((_ah), (_chan), (_iqcal)))
+#if HAL_ABI_VERSION >= 0x08111000
+#define ath_hal_calibrateN(_ah, _chan, _lcal, _isdone) \
+ ((*(_ah)->ah_perCalibrationN)((_ah), (_chan), 0x1, (_lcal), (_isdone)))
+#define ath_hal_calreset(_ah, _chan) \
+ ((*(_ah)->ah_resetCalValid)((_ah), (_chan)))
+#else
+#define ath_hal_calibrateN(_ah, _chan, _lcal, _isdone) \
+ ath_hal_calibrate(_ah, _chan, _isdone)
+#define ath_hal_calreset(_ah, _chan) (0)
+#endif
#define ath_hal_setledstate(_ah, _state) \
((*(_ah)->ah_setLedState)((_ah), (_state)))
#define ath_hal_beaconinit(_ah, _nextb, _bperiod) \
OpenPOWER on IntegriCloud