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;
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to