On Sun, Jul 08, 2012 at 10:11:44AM +0200, Stefan Sperling wrote:
> The rt2560 part of the ral driver uses a prio queue for management
> frames and a tx queue for data frames.
> 
> Both queues currently use a shared flag to tell the network stack that they
> are full (IFF_OACTIVE). It seems that IFF_OACTIVE can get cleared by the
> interrupt handler for one queue while the other queue is still loaded,
> so the network layer might try to push more frames down while we can't
> actually handle them. With the diff below we reset IFF_OACTIVE only if
> both prio and tx queues have been drained.
> 
> Also, don't reset the tx watchdog counter if the tx/prio queues still have
> frames queued when we exit the frame-processing loop in either interrupt
> handler. Else, it seems the watchdog might fail to run rt2560_init() even
> though we failed to transmit some frames.

Updated version that includes similar fixes for the rt2661 variants.

This seems to help soekris-based ral APs that get stuck with the OACTIVE
flag set (see the flags line in "ifconfig ral0" output when the AP stops
responding) and then require "ifconfig ral0 down up" to recover.

It would be great to get some more testing. Thanks!

Index: rt2560.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/rt2560.c,v
retrieving revision 1.58
diff -u -p -r1.58 rt2560.c
--- rt2560.c    22 Feb 2011 20:05:03 -0000      1.58
+++ rt2560.c    10 Jul 2012 15:34:21 -0000
@@ -995,9 +995,14 @@ rt2560_tx_intr(struct rt2560_softc *sc)
                sc->txq.next = (sc->txq.next + 1) % RT2560_TX_RING_COUNT;
        }
 
-       sc->sc_tx_timer = 0;
-       ifp->if_flags &= ~IFF_OACTIVE;
-       rt2560_start(ifp);
+       if (sc->txq.queued == 0 && sc->prioq.queued == 0)
+               sc->sc_tx_timer = 0;
+       if (sc->txq.queued < RT2560_TX_RING_COUNT - 1) {
+               sc->sc_flags &= ~RT2560_DATA_OACTIVE;
+               if (!(sc->sc_flags & (RT2560_DATA_OACTIVE|RT2560_PRIO_OACTIVE)))
+                       ifp->if_flags &= ~IFF_OACTIVE;
+               rt2560_start(ifp);
+       }
 }
 
 void
@@ -1061,9 +1066,14 @@ rt2560_prio_intr(struct rt2560_softc *sc
                sc->prioq.next = (sc->prioq.next + 1) % RT2560_PRIO_RING_COUNT;
        }
 
-       sc->sc_tx_timer = 0;
-       ifp->if_flags &= ~IFF_OACTIVE;
-       rt2560_start(ifp);
+       if (sc->txq.queued == 0 && sc->prioq.queued == 0)
+               sc->sc_tx_timer = 0;
+       if (sc->prioq.queued < RT2560_PRIO_RING_COUNT) {
+               sc->sc_flags &= ~RT2560_PRIO_OACTIVE;
+               if (!(sc->sc_flags & (RT2560_DATA_OACTIVE|RT2560_PRIO_OACTIVE)))
+                       ifp->if_flags &= ~IFF_OACTIVE;
+               rt2560_start(ifp);
+       }
 }
 
 /*
@@ -1931,6 +1941,7 @@ rt2560_start(struct ifnet *ifp)
                if (m0 != NULL) {
                        if (sc->prioq.queued >= RT2560_PRIO_RING_COUNT) {
                                ifp->if_flags |= IFF_OACTIVE;
+                               sc->sc_flags |= RT2560_PRIO_OACTIVE;
                                break;
                        }
                        IF_DEQUEUE(&ic->ic_mgtq, m0);
@@ -1952,6 +1963,7 @@ rt2560_start(struct ifnet *ifp)
                                break;
                        if (sc->txq.queued >= RT2560_TX_RING_COUNT - 1) {
                                ifp->if_flags |= IFF_OACTIVE;
+                               sc->sc_flags |= RT2560_DATA_OACTIVE;
                                break;
                        }
                        IFQ_DEQUEUE(&ifp->if_snd, m0);
@@ -2685,6 +2697,7 @@ rt2560_stop(struct ifnet *ifp, int disab
        struct ieee80211com *ic = &sc->sc_ic;
 
        sc->sc_tx_timer = 0;
+       sc->sc_flags &= ~(RT2560_PRIO_OACTIVE|RT2560_DATA_OACTIVE);
        ifp->if_timer = 0;
        ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
 
Index: rt2560var.h
===================================================================
RCS file: /cvs/src/sys/dev/ic/rt2560var.h,v
retrieving revision 1.9
diff -u -p -r1.9 rt2560var.h
--- rt2560var.h 7 Sep 2010 16:21:42 -0000       1.9
+++ rt2560var.h 7 Jul 2012 15:58:58 -0000
@@ -116,6 +116,8 @@ struct rt2560_softc {
 #define RT2560_ENABLED         (1 << 0)
 #define RT2560_UPDATE_SLOT     (1 << 1)
 #define RT2560_SET_SLOTTIME    (1 << 2)
+#define RT2560_PRIO_OACTIVE    (1 << 3)
+#define RT2560_DATA_OACTIVE    (1 << 4)
 
        int                     sc_tx_timer;
 
Index: rt2661.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/rt2661.c,v
retrieving revision 1.65
diff -u -p -r1.65 rt2661.c
--- rt2661.c    18 Mar 2011 06:05:21 -0000      1.65
+++ rt2661.c    10 Jul 2012 15:38:03 -0000
@@ -986,9 +986,18 @@ rt2661_tx_intr(struct rt2661_softc *sc)
                        txq->stat = 0;
        }
 
-       sc->sc_tx_timer = 0;
-       ifp->if_flags &= ~IFF_OACTIVE;
-       rt2661_start(ifp);
+       if (sc->mgtq.queued == 0 && sc->txq[0].queued == 0)
+               sc->sc_tx_timer = 0;
+       if (sc->mgtq.queued < RT2661_MGT_RING_COUNT &&
+           sc->txq[0].queued < RT2661_TX_RING_COUNT - 1) {
+               if (sc->mgtq.queued < RT2661_MGT_RING_COUNT)
+                       sc->sc_flags &= ~RT2661_MGT_OACTIVE;
+               if (sc->txq[0].queued < RT2661_TX_RING_COUNT - 1)
+                       sc->sc_flags &= ~RT2661_DATA_OACTIVE;
+               if (!(sc->sc_flags & (RT2661_MGT_OACTIVE|RT2661_DATA_OACTIVE)))
+                       ifp->if_flags &= ~IFF_OACTIVE;
+               rt2661_start(ifp);
+       }
 }
 
 void
@@ -1805,6 +1814,7 @@ rt2661_start(struct ifnet *ifp)
                if (m0 != NULL) {
                        if (sc->mgtq.queued >= RT2661_MGT_RING_COUNT) {
                                ifp->if_flags |= IFF_OACTIVE;
+                               sc->sc_flags |= RT2661_MGT_OACTIVE;
                                break;
                        }
                        IF_DEQUEUE(&ic->ic_mgtq, m0);
@@ -1827,6 +1837,7 @@ rt2661_start(struct ifnet *ifp)
                        if (sc->txq[0].queued >= RT2661_TX_RING_COUNT - 1) {
                                /* there is no place left in this ring */
                                ifp->if_flags |= IFF_OACTIVE;
+                               sc->sc_flags |= RT2661_DATA_OACTIVE;
                                break;
                        }
                        IFQ_DEQUEUE(&ifp->if_snd, m0);
@@ -2602,6 +2613,7 @@ rt2661_stop(struct ifnet *ifp, int disab
        int ac;
 
        sc->sc_tx_timer = 0;
+       sc->sc_flags &= ~(RT2661_MGT_OACTIVE|RT2661_DATA_OACTIVE);
        ifp->if_timer = 0;
        ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
 
Index: rt2661var.h
===================================================================
RCS file: /cvs/src/sys/dev/ic/rt2661var.h,v
retrieving revision 1.14
diff -u -p -r1.14 rt2661var.h
--- rt2661var.h 18 Mar 2011 06:05:21 -0000      1.14
+++ rt2661var.h 10 Jul 2012 13:17:30 -0000
@@ -111,6 +111,8 @@ struct rt2661_softc {
 #define RT2661_UPDATE_SLOT     (1 << 1)
 #define RT2661_SET_SLOTTIME    (1 << 2)
 #define RT2661_FWLOADED                (1 << 3)
+#define RT2661_MGT_OACTIVE     (1 << 4)
+#define RT2661_DATA_OACTIVE    (1 << 5)
 
        int                             sc_tx_timer;

Reply via email to