svn commit: r259061 - head/sys/dev/iwn
Adrian Chadd
adrian at FreeBSD.org
Sat Dec 7 08:03:11 UTC 2013
Author: adrian
Date: Sat Dec 7 08:03:10 2013
New Revision: 259061
URL: http://svnweb.freebsd.org/changeset/base/259061
Log:
Begin fleshing out some code to handle tracking PLCP error rates
in preparation for the scan based retune logic.
The linux iwlwifi driver does a rescan (onto a non-active channel)
to force an RF retune when the PLCP error rates exceed a certain threshold.
* Add code to track HT PLCP rate errors;
* Separate out the PLCP error count fetch and update so the delta
can be used when checking for PLCP error rates;
* Implement the PLCP error logic from iwlwifi;
* For now, just print out whenever the error rate exceeds the
threshold.
The actual scan based retune will take a bit more effort; the scan
command code right now assumes that a scan state is passed in.
This does need to change to be more flexible (both for this and
in preparation for scanning multiple channels at once.)
Tested:
* 5100 (STA mode)
* 2200 (STA mode)
* 2230 (STA mode)
Modified:
head/sys/dev/iwn/if_iwn.c
head/sys/dev/iwn/if_iwnvar.h
Modified: head/sys/dev/iwn/if_iwn.c
==============================================================================
--- head/sys/dev/iwn/if_iwn.c Sat Dec 7 07:12:37 2013 (r259060)
+++ head/sys/dev/iwn/if_iwn.c Sat Dec 7 08:03:10 2013 (r259061)
@@ -272,7 +272,10 @@ static int iwn4965_set_gains(struct iwn_
static int iwn5000_set_gains(struct iwn_softc *);
static void iwn_tune_sensitivity(struct iwn_softc *,
const struct iwn_rx_stats *);
+static void iwn_save_stats_counters(struct iwn_softc *,
+ const struct iwn_stats *);
static int iwn_send_sensitivity(struct iwn_softc *);
+static void iwn_check_rx_recovery(struct iwn_softc *, struct iwn_stats *);
static int iwn_set_pslevel(struct iwn_softc *, int, int, int);
static int iwn_send_btcoex(struct iwn_softc *);
static int iwn_send_advanced_btcoex(struct iwn_softc *);
@@ -3187,13 +3190,39 @@ iwn_rx_statistics(struct iwn_softc *sc,
if (calib->state == IWN_CALIB_STATE_ASSOC)
iwn_collect_noise(sc, &stats->rx.general);
- else if (calib->state == IWN_CALIB_STATE_RUN)
+ else if (calib->state == IWN_CALIB_STATE_RUN) {
iwn_tune_sensitivity(sc, &stats->rx);
+ /*
+ * XXX TODO: Only run the RX recovery if we're associated!
+ */
+ iwn_check_rx_recovery(sc, stats);
+ iwn_save_stats_counters(sc, stats);
+ }
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__);
}
/*
+ * Save the relevant statistic counters for the next calibration
+ * pass.
+ */
+static void
+iwn_save_stats_counters(struct iwn_softc *sc, const struct iwn_stats *rs)
+{
+ struct iwn_calib_state *calib = &sc->calib;
+
+ /* Save counters values for next call. */
+ calib->bad_plcp_cck = le32toh(rs->rx.cck.bad_plcp);
+ calib->fa_cck = le32toh(rs->rx.cck.fa);
+ calib->bad_plcp_ht = le32toh(rs->rx.ht.bad_plcp);
+ calib->bad_plcp_ofdm = le32toh(rs->rx.ofdm.bad_plcp);
+ calib->fa_ofdm = le32toh(rs->rx.ofdm.fa);
+
+ /* Last time we received these tick values */
+ sc->last_calib_ticks = ticks;
+}
+
+/*
* Process a TX_DONE firmware notification. Unfortunately, the 4965AGN
* and 5000 adapters have different incompatible TX status formats.
*/
@@ -5652,10 +5681,6 @@ iwn_tune_sensitivity(struct iwn_softc *s
fa += le32toh(stats->ofdm.fa) - calib->fa_ofdm;
fa *= 200 * IEEE80211_DUR_TU; /* 200TU */
- /* Save counters values for next call. */
- calib->bad_plcp_ofdm = le32toh(stats->ofdm.bad_plcp);
- calib->fa_ofdm = le32toh(stats->ofdm.fa);
-
if (fa > 50 * rxena) {
/* High false alarm count, decrease sensitivity. */
DPRINTF(sc, IWN_DEBUG_CALIBRATE,
@@ -5709,10 +5734,6 @@ iwn_tune_sensitivity(struct iwn_softc *s
fa += le32toh(stats->cck.fa) - calib->fa_cck;
fa *= 200 * IEEE80211_DUR_TU; /* 200TU */
- /* Save counters values for next call. */
- calib->bad_plcp_cck = le32toh(stats->cck.bad_plcp);
- calib->fa_cck = le32toh(stats->cck.fa);
-
if (fa > 50 * rxena) {
/* High false alarm count, decrease sensitivity. */
DPRINTF(sc, IWN_DEBUG_CALIBRATE,
@@ -5818,6 +5839,86 @@ send:
}
/*
+ * Look at the increase of PLCP errors over time; if it exceeds
+ * a programmed threshold then trigger an RF retune.
+ */
+static void
+iwn_check_rx_recovery(struct iwn_softc *sc, struct iwn_stats *rs)
+{
+ int32_t delta_ofdm, delta_ht, delta_cck;
+ struct iwn_calib_state *calib = &sc->calib;
+ int delta_ticks, cur_ticks;
+ int delta_msec;
+ int thresh;
+
+ /*
+ * Calculate the difference between the current and
+ * previous statistics.
+ */
+ delta_cck = le32toh(rs->rx.cck.bad_plcp) - calib->bad_plcp_cck;
+ delta_ofdm = le32toh(rs->rx.ofdm.bad_plcp) - calib->bad_plcp_ofdm;
+ delta_ht = le32toh(rs->rx.ht.bad_plcp) - calib->bad_plcp_ht;
+
+ /*
+ * Calculate the delta in time between successive statistics
+ * messages. Yes, it can roll over; so we make sure that
+ * this doesn't happen.
+ *
+ * XXX go figure out what to do about rollover
+ * XXX go figure out what to do if ticks rolls over to -ve instead!
+ * XXX go stab signed integer overflow undefined-ness in the face.
+ */
+ cur_ticks = ticks;
+ delta_ticks = cur_ticks - sc->last_calib_ticks;
+
+ /*
+ * If any are negative, then the firmware likely reset; so just
+ * bail. We'll pick this up next time.
+ */
+ if (delta_cck < 0 || delta_ofdm < 0 || delta_ht < 0 || delta_ticks < 0)
+ return;
+
+ /*
+ * delta_ticks is in ticks; we need to convert it up to milliseconds
+ * so we can do some useful math with it.
+ */
+ delta_msec = ticks_to_msecs(delta_ticks);
+
+ /*
+ * Calculate what our threshold is given the current delta_msec.
+ */
+ thresh = sc->base_params->plcp_err_threshold * delta_msec;
+
+ DPRINTF(sc, IWN_DEBUG_STATE,
+ "%s: time delta: %d; cck=%d, ofdm=%d, ht=%d, total=%d, thresh=%d\n",
+ __func__,
+ delta_msec,
+ delta_cck,
+ delta_ofdm,
+ delta_ht,
+ (delta_msec + delta_cck + delta_ofdm + delta_ht),
+ thresh);
+
+ /*
+ * If we need a retune, then schedule a single channel scan
+ * to a channel that isn't the currently active one!
+ *
+ * The math from linux iwlwifi:
+ *
+ * if ((delta * 100 / msecs) > threshold)
+ */
+ if (thresh > 0 && (delta_cck + delta_ofdm + delta_ht) * 100 > thresh) {
+ device_printf(sc->sc_dev,
+ "%s: PLCP error threshold raw (%d) comparison (%d) "
+ "over limit (%d); retune!\n",
+ __func__,
+ (delta_cck + delta_ofdm + delta_ht),
+ (delta_cck + delta_ofdm + delta_ht) * 100,
+ thresh);
+ }
+}
+
+/*
* Set STA mode power saving level (between 0 and 5).
* Level 0 is CAM (Continuously Aware Mode), 5 is for maximum power saving.
*/
@@ -7048,10 +7149,10 @@ iwn5000_query_calibration(struct iwn_sof
int error;
memset(&cmd, 0, sizeof cmd);
- cmd.ucode.once.enable = 0xffffffff;
- cmd.ucode.once.start = 0xffffffff;
- cmd.ucode.once.send = 0xffffffff;
- cmd.ucode.flags = 0xffffffff;
+ cmd.ucode.once.enable = htole32(0xffffffff);
+ cmd.ucode.once.start = htole32(0xffffffff);
+ cmd.ucode.once.send = htole32(0xffffffff);
+ cmd.ucode.flags = htole32(0xffffffff);
DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: sending calibration query\n",
__func__);
error = iwn_cmd(sc, IWN5000_CMD_CALIB_CONFIG, &cmd, sizeof cmd, 0);
@@ -7107,7 +7208,7 @@ iwn5000_send_wimax_coex(struct iwn_softc
{
struct iwn5000_wimax_coex wimax;
-#ifdef notyet
+#if 0
if (sc->hw_type == IWN_HW_REV_TYPE_6050) {
/* Enable WiMAX coexistence for combo adapters. */
wimax.flags =
Modified: head/sys/dev/iwn/if_iwnvar.h
==============================================================================
--- head/sys/dev/iwn/if_iwnvar.h Sat Dec 7 07:12:37 2013 (r259060)
+++ head/sys/dev/iwn/if_iwnvar.h Sat Dec 7 08:03:10 2013 (r259061)
@@ -163,6 +163,7 @@ struct iwn_calib_state {
uint32_t bad_plcp_cck;
uint32_t fa_cck;
uint32_t low_fa;
+ uint32_t bad_plcp_ht;
uint8_t cck_state;
#define IWN_CCK_STATE_INIT 0
#define IWN_CCK_STATE_LOFA 1
@@ -310,9 +311,11 @@ struct iwn_softc {
struct task sc_radioon_task;
struct task sc_radiooff_task;
+ /* Calibration information */
struct callout calib_to;
int calib_cnt;
struct iwn_calib_state calib;
+ int last_calib_ticks;
struct callout watchdog_to;
struct callout ct_kill_exit_to;
struct iwn_fw_info fw;
More information about the svn-src-all
mailing list