Add support in ONOE/AMRR for drivers that can't provide per TX statistics:
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Tue, 24 Oct 2006 14:39:45 +0000 (14:39 +0000)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Tue, 24 Oct 2006 14:39:45 +0000 (14:39 +0000)
- Add callback function pointer ieee80211_ratectl_state.rc_st_state, which
  will be called periodically by ONOE/AMRR during their internal state
  updating.  This callback function pointer should return a
  ieee80211_ratectl_stats struct, which provides statistics concerning TX.
- Add ieee80211_ratectl_state.rc_st_valid_stats bitmask.  It is used to
  tell ONOE/AMRR which fields of ieee80211_ratectl_stats are valid.
- Make ONOE/AMRR spit out a warning message if driver can't provide per TX
  statistics and the statistics in ieee80211_ratectl_stats are not enough to
  do proper TX rate control.

Drivers that can't provide per TX statistics should setup
ieee80211_ratectl_state.rc_st_state and
ieee80211_ratectl_state.rc_st_valid_stats before ieee80211_ifattach().

Add ieee80211_ratectl_state.rc_st_param, it could be used by drivers to
override TX rate control algorithm's default tunable values.  This field should
be allocated, setup and freed in ieee80211_ratectl_state.rc_st_change.  Drivers
that is going to override TX rate control algorithm's default tunable values
should include specific TX rate control algorithm's parameter header file
e.g. netproto/802_11/wlan_ratectl/ieee80211_amrr_param.h

sys/netproto/802_11/ieee80211_ratectl.h
sys/netproto/802_11/wlan_ratectl/amrr/ieee80211_amrr_param.h [new file with mode: 0644]
sys/netproto/802_11/wlan_ratectl/amrr/ieee80211_ratectl_amrr.c
sys/netproto/802_11/wlan_ratectl/onoe/ieee80211_onoe_param.h [new file with mode: 0644]
sys/netproto/802_11/wlan_ratectl/onoe/ieee80211_ratectl_onoe.c

index 8f86951..e95ef25 100644 (file)
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/netproto/802_11/ieee80211_ratectl.h,v 1.2 2006/10/21 08:37:03 sephe Exp $
+ * $DragonFly: src/sys/netproto/802_11/ieee80211_ratectl.h,v 1.3 2006/10/24 14:39:44 sephe Exp $
  */
 
 #ifndef _NET80211_IEEE80211_RATECTL_H
 #define _NET80211_IEEE80211_RATECTL_H
 
+struct ieee80211_ratectl_stats;
+
 struct ieee80211_ratectl_state {
        void            *rc_st_ctx;
-       u_int           rc_st_ratectl;          /* see IEEE80211_RATECTL_ */
-       uint32_t        rc_st_ratectl_cap;      /* see IEEE80211_RATECTL_CAP_ */
+       void            *rc_st_param;
+       u_int           rc_st_ratectl;     /* see IEEE80211_RATECTL_ */
+       uint32_t        rc_st_ratectl_cap; /* see IEEE80211_RATECTL_CAP_ */
+       uint64_t        rc_st_valid_stats; /* see IEEE80211_RATECTL_STATS_ */
        void            (*rc_st_change)(struct ieee80211com *, u_int, u_int);
+       void            (*rc_st_stats)(struct ieee80211com *,
+                                      struct ieee80211_node *,
+                                      struct ieee80211_ratectl_stats *);
 };
 
 struct ieee80211_ratectl_res {
@@ -49,6 +56,24 @@ struct ieee80211_ratectl_res {
        int             rc_res_tries;
 };
 
+#define IEEE80211_RATECTL_STATS_RES            0x1
+#define IEEE80211_RATECTL_STATS_PKT_NORETRY    0x2
+#define IEEE80211_RATECTL_STATS_PKT_OK         0x4
+#define IEEE80211_RATECTL_STATS_PKT_ERR                0x8
+#define IEEE80211_RATECTL_STATS_RETRIES                0x10
+
+#define IEEE80211_RATEIDX_MAX          5
+
+struct ieee80211_ratectl_stats {
+       struct ieee80211_ratectl_res    stats_res[IEEE80211_RATEIDX_MAX];
+       int                             stats_res_len;
+       int                             stats_pkt_noretry;
+       int                             stats_pkt_ok;
+       int                             stats_pkt_err;
+       int                             stats_short_retries;
+       int                             stats_long_retries;
+};
+
 struct ieee80211_ratectl {
        const char      *rc_name;
        u_int           rc_ratectl;     /* see IEEE80211_RATECTL_ */
@@ -75,8 +100,6 @@ struct ieee80211_ratectl {
 #define IEEE80211_RATECTL_AMRR         2
 #define IEEE80211_RATECTL_MAX          3
 
-#define IEEE80211_RATEIDX_MAX          5
-
 #define IEEE80211_RATECTL_CAP(v)       (1 << (v))
 
 #define _IEEE80211_RATECTL_CAP(n)      \
diff --git a/sys/netproto/802_11/wlan_ratectl/amrr/ieee80211_amrr_param.h b/sys/netproto/802_11/wlan_ratectl/amrr/ieee80211_amrr_param.h
new file mode 100644 (file)
index 0000000..63d4167
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2004 INRIA
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD: src/sys/dev/ath/ath_rate/amrr/amrr.h,v 1.2 2004/12/31 22:41:45 sam Exp $
+ * $DragonFly: src/sys/netproto/802_11/wlan_ratectl/amrr/ieee80211_amrr_param.h,v 1.1 2006/10/24 14:39:44 sephe Exp $
+ */
+
+#ifndef _IEEE80211_AMRR_PARAM_H
+#define _IEEE80211_AMRR_PARAM_H
+
+struct ieee80211_amrr_param {
+       int     amrr_interval;  /* unit: millisecond */
+       int     amrr_max_success_threshold;
+       int     amrr_min_success_threshold;
+};
+
+#define IEEE80211_AMRR_INTERVAL                1000    /* 1 second */
+#define IEEE80211_AMRR_MAX_SUCCESS_THR 10
+#define IEEE80211_AMRR_MIN_SUCCESS_THR 1
+
+#define IEEE80211_AMRR_PARAM_SETUP(param)      \
+do {                                           \
+       (param)->amrr_interval =                \
+               IEEE80211_AMRR_INTERVAL;        \
+       (param)->amrr_max_success_threshold =   \
+               IEEE80211_AMRR_MAX_SUCCESS_THR; \
+       (param)->amrr_min_success_threshold =   \
+               IEEE80211_AMRR_MIN_SUCCESS_THR; \
+} while (0)
+
+#endif /* !_IEEE80211_AMRR_PARAM_H */
index d06e348..791f5e2 100644 (file)
@@ -35,7 +35,7 @@
  * THE POSSIBILITY OF SUCH DAMAGES.
  *
  * $FreeBSD: src/sys/dev/ath/ath_rate/amrr/amrr.c,v 1.8.2.3 2006/02/24 19:51:11 sam Exp $
- * $DragonFly: src/sys/netproto/802_11/wlan_ratectl/amrr/ieee80211_ratectl_amrr.c,v 1.4 2006/10/21 08:37:04 sephe Exp $
+ * $DragonFly: src/sys/netproto/802_11/wlan_ratectl/amrr/ieee80211_ratectl_amrr.c,v 1.5 2006/10/24 14:39:44 sephe Exp $
  */
 
 /*
@@ -57,6 +57,7 @@
 #include <net/if_arp.h>
 
 #include <netproto/802_11/ieee80211_var.h>
+#include <netproto/802_11/wlan_ratectl/amrr/ieee80211_amrr_param.h>
 #include <netproto/802_11/wlan_ratectl/amrr/ieee80211_ratectl_amrr.h>
 
 #define        AMRR_DEBUG
 #define        DPRINTF(asc, lv, fmt, ...)
 #endif
 
+#define AMRR_REQUIRE_STATS1    (IEEE80211_RATECTL_STATS_RES |          \
+                                IEEE80211_RATECTL_STATS_PKT_NORETRY)
+#define AMRR_REQUIRE_STATS2    (IEEE80211_RATECTL_STATS_PKT_NORETRY |  \
+                                IEEE80211_RATECTL_STATS_PKT_OK |       \
+                                IEEE80211_RATECTL_STATS_PKT_ERR |      \
+                                IEEE80211_RATECTL_STATS_RETRIES)
+#define AMRR_MEET_REQUIRE_STATS1(stats_mask)   \
+       (((stats_mask) & AMRR_REQUIRE_STATS1) == AMRR_REQUIRE_STATS1)
+#define AMRR_MEET_REQUIRE_STATS2(stats_mask)   \
+       (((stats_mask) & AMRR_REQUIRE_STATS2) == AMRR_REQUIRE_STATS2)
+
 static void    *amrr_attach(struct ieee80211com *);
 static void    amrr_detach(void *);
 static void    amrr_data_alloc(struct ieee80211_node *);
@@ -88,6 +100,7 @@ static void  amrr_update(struct amrr_softc *, struct ieee80211_node *, int);
 static void    amrr_start(struct amrr_softc *, struct ieee80211_node *);
 static void    amrr_tick(void *);
 static void    amrr_ratectl(void *, struct ieee80211_node *);
+static void    amrr_gather_stats(struct amrr_softc *, struct ieee80211_node *);
 
 static const struct ieee80211_ratectl amrr = {
        .rc_name        = "amrr",
@@ -308,6 +321,33 @@ amrr_newstate(void *arg, enum ieee80211_state state)
        }
 }
 
+static void
+amrr_gather_stats(struct amrr_softc *asc, struct ieee80211_node *ni)
+{
+       struct ieee80211com *ic = asc->ic;
+       const struct ieee80211_ratectl_state *st = &ic->ic_ratectl;
+       struct amrr_data *ad = ni->ni_rate_data;
+       struct ieee80211_ratectl_stats stats;
+       u_int total_tries = 0;
+
+       st->rc_st_stats(ic, ni, &stats);
+
+       if (AMRR_MEET_REQUIRE_STATS1(st->rc_st_valid_stats)) {
+               int i;
+
+               for (i = 0; i < stats.stats_res_len; ++i)
+                       total_tries += stats.stats_res[i].rc_res_tries;
+       } else if (AMRR_MEET_REQUIRE_STATS2(st->rc_st_valid_stats)) {
+               total_tries = stats.stats_pkt_ok +
+                             stats.stats_pkt_err +
+                             stats.stats_short_retries +
+                             stats.stats_long_retries;
+       }
+
+       ad->ad_tx_cnt += total_tries;
+       ad->ad_tx_failure_cnt += (total_tries - stats.stats_pkt_noretry);
+}
+
 /* 
  * Examine and potentially adjust the transmit rate.
  */
@@ -315,6 +355,7 @@ static void
 amrr_ratectl(void *arg, struct ieee80211_node *ni)
 {
        struct amrr_softc *asc = arg;
+       const struct ieee80211_ratectl_state *st = &asc->ic->ic_ratectl;
        struct amrr_data *ad = ni->ni_rate_data;
        int old_rate;
 
@@ -331,6 +372,13 @@ amrr_ratectl(void *arg, struct ieee80211_node *ni)
 #define is_min_rate(ni)        (ni->ni_txrate == 0)
 
        old_rate = ni->ni_txrate;
+
+       if (st->rc_st_stats != NULL) {
+               if (!AMRR_MEET_REQUIRE_STATS1(st->rc_st_valid_stats) &&
+                   !AMRR_MEET_REQUIRE_STATS2(st->rc_st_valid_stats))
+                       return;
+               amrr_gather_stats(asc, ni);
+       }
   
        DPRINTF(asc, 10, "tx_cnt: %u tx_failure_cnt: %u -- "
                "threshold: %d\n",
@@ -408,14 +456,24 @@ amrr_tick(void *arg)
 static void
 amrr_sysctl_attach(struct amrr_softc *asc)
 {
+       struct ieee80211com *ic = asc->ic;
+       struct ieee80211_amrr_param *param;
+
+       param = ic->ic_ratectl.rc_st_param;
+       if (param != NULL) {
+               asc->interval = param->amrr_interval;
+               asc->max_success_threshold = param->amrr_max_success_threshold;
+               asc->min_success_threshold = param->amrr_min_success_threshold;
+       } else {
+               asc->interval = IEEE80211_AMRR_INTERVAL;
+               asc->max_success_threshold = IEEE80211_AMRR_MAX_SUCCESS_THR;
+               asc->min_success_threshold = IEEE80211_AMRR_MIN_SUCCESS_THR;
+       }
        asc->debug = 0;
-       asc->interval = 1000;
-       asc->max_success_threshold = 10;
-       asc->min_success_threshold = 1;
 
        sysctl_ctx_init(&asc->sysctl_ctx);
        asc->sysctl_oid = SYSCTL_ADD_NODE(&asc->sysctl_ctx,
-               SYSCTL_CHILDREN(asc->ic->ic_sysctl_oid),
+               SYSCTL_CHILDREN(ic->ic_sysctl_oid),
                OID_AUTO, "amrr_ratectl", CTLFLAG_RD, 0, "");
        if (asc->sysctl_oid == NULL) {
                printf("wlan_ratectl_amrr: create sysctl tree failed\n");
@@ -444,8 +502,16 @@ amrr_sysctl_attach(struct amrr_softc *asc)
 static void *
 amrr_attach(struct ieee80211com *ic)
 {
+       const struct ieee80211_ratectl_state *st = &ic->ic_ratectl;
        struct amrr_softc *asc;
 
+       if (st->rc_st_stats != NULL &&
+           !AMRR_MEET_REQUIRE_STATS1(st->rc_st_valid_stats) &&
+           !AMRR_MEET_REQUIRE_STATS2(st->rc_st_valid_stats)) {
+               if_printf(&ic->ic_if, "WARNING: %s needs more average "
+                         "statistics to work properly\n", amrr.rc_name);
+       }
+
        amrr_nrefs++;
 
        asc = kmalloc(sizeof(struct amrr_softc), M_DEVBUF, M_WAITOK | M_ZERO);
diff --git a/sys/netproto/802_11/wlan_ratectl/onoe/ieee80211_onoe_param.h b/sys/netproto/802_11/wlan_ratectl/onoe/ieee80211_onoe_param.h
new file mode 100644 (file)
index 0000000..6682e1f
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD: src/sys/dev/ath/ath_rate/onoe/onoe.h,v 1.2 2004/12/31 22:41:45 sam Exp $
+ * $DragonFly: src/sys/netproto/802_11/wlan_ratectl/onoe/ieee80211_onoe_param.h,v 1.1 2006/10/24 14:39:45 sephe Exp $
+ */
+
+#ifndef _IEEE80211_ONOE_PARAM_H
+#define _IEEE80211_ONOE_PARAM_H
+
+struct ieee80211_onoe_param {
+       int     onoe_interval;  /* unit: millisecond */
+       int     onoe_raise;
+       int     onoe_raise_threshold;
+};
+
+#define IEEE80211_ONOE_INTERVAL                1000    /* 1 second */
+#define IEEE80211_ONOE_RAISE           10
+#define IEEE80211_ONOE_RAISE_THR       10
+
+#define IEEE80211_ONOE_PARAM_SETUP(param)      \
+do {                                           \
+       (param)->onoe_interval =                \
+               IEEE80211_ONOE_INTERVAL;        \
+       (param)->onoe_raise =                   \
+               IEEE80211_ONOE_RAISE;           \
+       (param)->onoe_raise_threshold =         \
+               IEEE80211_ONOE_RAISE_THR;       \
+} while (0)
+
+#endif /* !_IEEE80211_ONOE_PARAM_H */
index 8e6055c..12579ed 100644 (file)
@@ -34,7 +34,7 @@
  * THE POSSIBILITY OF SUCH DAMAGES.
  *
  * $FreeBSD: src/sys/dev/ath/ath_rate/onoe/onoe.c,v 1.8.2.3 2006/02/24 19:51:11 sam Exp $
- * $DragonFly: src/sys/netproto/802_11/wlan_ratectl/onoe/ieee80211_ratectl_onoe.c,v 1.3 2006/09/05 03:48:13 dillon Exp $
+ * $DragonFly: src/sys/netproto/802_11/wlan_ratectl/onoe/ieee80211_ratectl_onoe.c,v 1.4 2006/10/24 14:39:45 sephe Exp $
  */
 
 /*
@@ -53,6 +53,7 @@
 #include <net/if_arp.h>
 
 #include <netproto/802_11/ieee80211_var.h>
+#include <netproto/802_11/wlan_ratectl/onoe/ieee80211_onoe_param.h>
 #include <netproto/802_11/wlan_ratectl/onoe/ieee80211_ratectl_onoe.h>
 
 #define ONOE_DEBUG
 #define        DPRINTF(osc, lv, fmt, ...)
 #endif
 
+#define ONOE_REQUIRE_STATS     (IEEE80211_RATECTL_STATS_PKT_OK |       \
+                                IEEE80211_RATECTL_STATS_PKT_ERR |      \
+                                IEEE80211_RATECTL_STATS_RETRIES)
+#define ONOE_MEET_REQUIRE_STATS(stats_mask)    \
+       (((stats_mask) & ONOE_REQUIRE_STATS) == ONOE_REQUIRE_STATS)
+
 /*
  * Default parameters for the rate control algorithm.  These are
  * all tunable with sysctls.  The rate controller runs periodically
@@ -105,6 +112,7 @@ static void onoe_update(struct onoe_softc *, struct ieee80211_node *, int);
 static void    onoe_start(struct onoe_softc *, struct ieee80211_node *);
 static void    onoe_tick(void *);
 static void    onoe_ratectl(void *, struct ieee80211_node *);
+static void    onoe_gather_stats(struct onoe_softc *, struct ieee80211_node *);
 
 static const struct ieee80211_ratectl onoe = {
        .rc_name        = "onoe",
@@ -305,11 +313,27 @@ onoe_newstate(void *arg, enum ieee80211_state state)
        }
 }
 
+static void
+onoe_gather_stats(struct onoe_softc *osc, struct ieee80211_node *ni)
+{
+       struct onoe_data *od = ni->ni_rate_data;
+       struct ieee80211com *ic = osc->ic;
+       const struct ieee80211_ratectl_state *st = &ic->ic_ratectl;
+       struct ieee80211_ratectl_stats stats;
+
+       st->rc_st_stats(ic, ni, &stats);
+
+       od->od_tx_ok += stats.stats_pkt_ok;
+       od->od_tx_err += stats.stats_pkt_err;
+       od->od_tx_retr += stats.stats_long_retries + stats.stats_short_retries;
+}
+
 static void
 onoe_ratectl(void *arg, struct ieee80211_node *ni)
 {
        struct onoe_softc *osc = arg;
        struct onoe_data *od = ni->ni_rate_data;
+       const struct ieee80211_ratectl_state *st = &osc->ic->ic_ratectl;
        struct ieee80211_rateset *rs = &ni->ni_rates;
        int dir = 0, nrate, enough;
 
@@ -319,6 +343,12 @@ onoe_ratectl(void *arg, struct ieee80211_node *ni)
                return;
        }
 
+       if (st->rc_st_stats != NULL) {
+               if (!ONOE_MEET_REQUIRE_STATS(st->rc_st_valid_stats))
+                       return;
+               onoe_gather_stats(osc, ni);
+       }
+
        /*
         * Rate control
         * XXX: very primitive version.
@@ -404,9 +434,19 @@ onoe_tick(void *arg)
 static void
 onoe_sysctl_attach(struct onoe_softc *osc)
 {
-       osc->interval = 1000;
-       osc->raise = 10;
-       osc->raise_threshold = 10;
+       struct ieee80211com *ic = osc->ic;
+       struct ieee80211_onoe_param *param;
+
+       param = ic->ic_ratectl.rc_st_param;
+       if (param != NULL) {
+               osc->interval = param->onoe_interval;
+               osc->raise = param->onoe_raise;
+               osc->raise_threshold = param->onoe_raise_threshold;
+       } else {
+               osc->interval = IEEE80211_ONOE_INTERVAL;
+               osc->raise = IEEE80211_ONOE_RAISE;
+               osc->raise_threshold = IEEE80211_ONOE_RAISE_THR;
+       }
        osc->debug = 0;
 
        sysctl_ctx_init(&osc->sysctl_ctx);
@@ -441,8 +481,15 @@ onoe_sysctl_attach(struct onoe_softc *osc)
 static void *
 onoe_attach(struct ieee80211com *ic)
 {
+       const struct ieee80211_ratectl_state *st = &ic->ic_ratectl;
        struct onoe_softc *osc;
 
+       if (st->rc_st_stats != NULL &&
+           !ONOE_MEET_REQUIRE_STATS(st->rc_st_valid_stats)) {
+               if_printf(&ic->ic_if, "WARNING: %s needs more average "
+                         "statistics to work properly\n", onoe.rc_name);
+       }
+
        onoe_nrefs++;
 
        osc = kmalloc(sizeof(struct onoe_softc), M_DEVBUF, M_WAITOK | M_ZERO);