Author: avos
Date: Sun Mar 19 20:05:21 2017
New Revision: 315583
URL: https://svnweb.freebsd.org/changeset/base/315583

Log:
  net80211: add a timer to flush fast-frames queues.
  
  This should allow to drop 'ieee80211_ff_[age/flush]' calls from drivers
  (an additional call can be made from ieee80211_tx_complete()
  for non-default ieee80211_ffagemax values to prevent stalls -
  but it will require an additional counter for transmitted frames).
  
  Tested with RTL8821AU, STA mode (A-MSDU part only).
  
  Reviewed by:  adrian
  Differential Revision:        https://reviews.freebsd.org/D9984

Modified:
  head/sys/net80211/ieee80211_superg.c
  head/sys/net80211/ieee80211_superg.h

Modified: head/sys/net80211/ieee80211_superg.c
==============================================================================
--- head/sys/net80211/ieee80211_superg.c        Sun Mar 19 20:04:57 2017        
(r315582)
+++ head/sys/net80211/ieee80211_superg.c        Sun Mar 19 20:05:21 2017        
(r315583)
@@ -94,6 +94,33 @@ SYSCTL_PROC(_net_wlan, OID_AUTO, ffagema
        &ieee80211_ffagemax, 0, ieee80211_sysctl_msecs_ticks, "I",
        "max hold time for fast-frame staging (ms)");
 
+static void
+ff_age_all(void *arg, int npending)
+{
+       struct ieee80211com *ic = arg;
+
+       /* XXX cache timer value somewhere (racy) */
+       ieee80211_ff_age_all(ic, ieee80211_ffagemax + 1);
+}
+
+static void
+ff_check_cancel_age_timer(struct ieee80211com *ic)
+{
+       struct ieee80211_superg *sg = ic->ic_superg;
+
+       IEEE80211_FF_LOCK_ASSERT(ic);
+
+       if (sg->ff_stageq[WME_AC_VO].depth == 0 &&
+           sg->ff_stageq[WME_AC_VI].depth == 0 &&
+           sg->ff_stageq[WME_AC_BE].depth == 0 &&
+           sg->ff_stageq[WME_AC_BK].depth == 0) {
+               struct timeout_task *qtask = &sg->ff_qtimer;
+
+               /* NB: may be called from the task itself */
+               (void) taskqueue_cancel_timeout(ic->ic_tq, qtask, NULL);
+       }
+}
+
 void
 ieee80211_superg_attach(struct ieee80211com *ic)
 {
@@ -109,6 +136,7 @@ ieee80211_superg_attach(struct ieee80211
                    __func__);
                return;
        }
+       TIMEOUT_TASK_INIT(ic->ic_tq, &sg->ff_qtimer, 0, ff_age_all, ic);
        ic->ic_superg = sg;
 
        /*
@@ -122,12 +150,16 @@ ieee80211_superg_attach(struct ieee80211
 void
 ieee80211_superg_detach(struct ieee80211com *ic)
 {
-       IEEE80211_FF_LOCK_DESTROY(ic);
 
        if (ic->ic_superg != NULL) {
+               struct timeout_task *qtask = &ic->ic_superg->ff_qtimer;
+
+               while (taskqueue_cancel_timeout(ic->ic_tq, qtask, NULL) != 0)
+                       taskqueue_drain_timeout(ic->ic_tq, qtask);
                IEEE80211_FREE(ic->ic_superg, M_80211_VAP);
                ic->ic_superg = NULL;
        }
+       IEEE80211_FF_LOCK_DESTROY(ic);
 }
 
 void
@@ -647,9 +679,10 @@ ieee80211_ff_age(struct ieee80211com *ic
                sq->head = m->m_nextpkt;
                sq->depth--;
        }
-       if (m == NULL)
+       if (m == NULL) {
                sq->tail = NULL;
-       else
+               ff_check_cancel_age_timer(ic);
+       } else
                M_AGE_SUB(m, quanta);
        IEEE80211_FF_UNLOCK(ic);
 
@@ -668,8 +701,13 @@ stageq_add(struct ieee80211com *ic, stru
        if (sq->tail != NULL) {
                sq->tail->m_nextpkt = m;
                age -= M_AGE_GET(sq->head);
-       } else
+       } else {
                sq->head = m;
+
+               /* Do not restart the timer if task was already scheduled. */
+               struct timeout_task *qtask = &ic->ic_superg->ff_qtimer;
+               taskqueue_enqueue_timeout(ic->ic_tq, qtask, -age);
+       }
        KASSERT(age >= 0, ("age %d", age));
        M_AGE_SET(m, age);
        m->m_nextpkt = NULL;
@@ -694,6 +732,7 @@ stageq_remove(struct ieee80211com *ic, s
                        if (sq->tail == m)
                                sq->tail = mprev;
                        sq->depth--;
+                       ff_check_cancel_age_timer(ic);
                        return;
                }
                mprev = m;

Modified: head/sys/net80211/ieee80211_superg.h
==============================================================================
--- head/sys/net80211/ieee80211_superg.h        Sun Mar 19 20:04:57 2017        
(r315582)
+++ head/sys/net80211/ieee80211_superg.h        Sun Mar 19 20:05:21 2017        
(r315583)
@@ -66,6 +66,8 @@ struct ieee80211_stageq {
 struct ieee80211_superg {
        /* fast-frames staging q */
        struct ieee80211_stageq ff_stageq[WME_NUM_AC];
+       /* flush queues automatically */
+       struct timeout_task     ff_qtimer;
 };
 
 void   ieee80211_superg_attach(struct ieee80211com *);
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to