On Mon, Jul 16, 2012 at 02:35:05PM +0200, Stefan Sperling wrote: > Disregard this diff. It makes things even worse because it re-introduces > the problem where the interface gets stuck with OACTIVE set and isn't > reset automatically.
The problem with the prior diff was that it didn't look at the prio/tx queues separately. With the below diff we don't allow the watchdog to reset the interface as long as frames are leaving both queues. I'm still seeing device timeouts every so often. Not sure yet what the proper fix for the underlying bug is. It seems either one of the tx queues can get stuck, and now we're recovering automatically instead of requiring the user to down/up the interface. ok? Index: rt2560.c =================================================================== RCS file: /cvs/src/sys/dev/ic/rt2560.c,v retrieving revision 1.60 diff -u -p -r1.60 rt2560.c --- rt2560.c 13 Jul 2012 10:08:15 -0000 1.60 +++ rt2560.c 16 Jul 2012 11:03:33 -0000 @@ -926,6 +926,8 @@ rt2560_tx_intr(struct rt2560_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; struct ifnet *ifp = &ic->ic_if; + int prio_queued = sc->prioq.queued; + int tx_queued = sc->txq.queued; for (;;) { struct rt2560_tx_desc *desc = &sc->txq.desc[sc->txq.next]; @@ -995,7 +997,8 @@ rt2560_tx_intr(struct rt2560_softc *sc) sc->txq.next = (sc->txq.next + 1) % RT2560_TX_RING_COUNT; } - if (sc->txq.queued == 0 && sc->prioq.queued == 0) + if ((sc->prioq.queued == 0 && sc->txq.queued == 0) || + (sc->prioq.queued < prio_queued && sc->txq.queued < tx_queued)) sc->sc_tx_timer = 0; if (sc->txq.queued < RT2560_TX_RING_COUNT - 1) { sc->sc_flags &= ~RT2560_DATA_OACTIVE; Index: rt2661.c =================================================================== RCS file: /cvs/src/sys/dev/ic/rt2661.c,v retrieving revision 1.66 diff -u -p -r1.66 rt2661.c --- rt2661.c 13 Jul 2012 10:08:15 -0000 1.66 +++ rt2661.c 16 Jul 2012 13:27:26 -0000 @@ -156,6 +156,7 @@ int rt2661_prepare_beacon(struct rt2661 #endif void rt2661_enable_tsf_sync(struct rt2661_softc *); int rt2661_get_rssi(struct rt2661_softc *, uint8_t); +int rt2661_tx_queued(struct rt2661_softc *); static const struct { uint32_t reg; @@ -922,6 +923,18 @@ rt2661_eeprom_read(struct rt2661_softc * return val; } + +int +rt2661_tx_queued(struct rt2661_softc *sc) +{ + int i, queued = 0; + + for (i = 0; i < nitems(sc->txq); i++) + queued += sc->txq[i].queued; + + return queued; +} + void rt2661_tx_intr(struct rt2661_softc *sc) { @@ -931,6 +944,8 @@ rt2661_tx_intr(struct rt2661_softc *sc) struct rt2661_tx_data *data; struct rt2661_node *rn; int qid, retrycnt; + int mgt_queued = sc->mgtq.queued; + int tx_queued = rt2661_tx_queued(sc); for (;;) { const uint32_t val = RAL_READ(sc, RT2661_STA_CSR4); @@ -986,7 +1001,8 @@ rt2661_tx_intr(struct rt2661_softc *sc) txq->stat = 0; } - if (sc->mgtq.queued == 0 && sc->txq[0].queued == 0) + if ((sc->mgtq.queued == 0 && tx_queued == 0) || + (sc->mgtq.queued < mgt_queued && rt2661_tx_queued(sc) < tx_queued)) sc->sc_tx_timer = 0; if (sc->mgtq.queued < RT2661_MGT_RING_COUNT && sc->txq[0].queued < RT2661_TX_RING_COUNT - 1) {