On Nov 23 Roland Dreir sent a patch for interrupt handling, but it doesn't apply on -current since the file rt2661.c changed slightly a few weeks earlier (1.51, date: 2009/11/01).
This patch just changes Roland's patch to update against rt2661.c r1.51 from the OpenBSD repository instead of Roland's patch which is against his private GIT repo. I've been running with this for just over a day, including some time copying kernels and snaps both ways non-stop (after removing the ifconfig down/up from crontab). It has locked up only twice in 24 hrs, a definite improvement. Index: rt2661.c =================================================================== RCS file: /cvs/src/sys/dev/ic/rt2661.c,v retrieving revision 1.51 diff -N -u -p rt2661.c --- rt2661.c 1 Nov 2009 12:08:36 -0000 1.51 +++ rt2661.c 28 Dec 2009 21:16:06 -0000 @@ -97,9 +97,8 @@ void rt2661_newassoc(struct ieee80211com *, struct ie int rt2661_newstate(struct ieee80211com *, enum ieee80211_state, int); uint16_t rt2661_eeprom_read(struct rt2661_softc *, uint8_t); +void rt2661_free_tx_desc(struct rt2661_softc *, struct rt2661_tx_ring *); void rt2661_tx_intr(struct rt2661_softc *); -void rt2661_tx_dma_intr(struct rt2661_softc *, - struct rt2661_tx_ring *); void rt2661_rx_intr(struct rt2661_softc *); #ifndef IEEE80211_STA_ONLY void rt2661_mcu_beacon_expire(struct rt2661_softc *); @@ -115,7 +114,7 @@ uint16_t rt2661_txtime(int, int, uint32_t); uint8_t rt2661_plcp_signal(int); void rt2661_setup_tx_desc(struct rt2661_softc *, struct rt2661_tx_desc *, uint32_t, uint16_t, int, int, - const bus_dma_segment_t *, int, int); + const bus_dma_segment_t *, int, int, int); int rt2661_tx_mgt(struct rt2661_softc *, struct mbuf *, struct ieee80211_node *); int rt2661_tx_data(struct rt2661_softc *, struct mbuf *, @@ -376,7 +375,7 @@ rt2661_alloc_tx_ring(struct rt2661_softc *sc, struct r ring->count = count; ring->queued = 0; - ring->cur = ring->next = ring->stat = 0; + ring->cur = ring->stat = 0; error = bus_dmamap_create(sc->sc_dmat, count * RT2661_TX_DESC_SIZE, 1, count * RT2661_TX_DESC_SIZE, 0, BUS_DMA_NOWAIT, &ring->map); @@ -470,7 +469,7 @@ rt2661_reset_tx_ring(struct rt2661_softc *sc, struct r BUS_DMASYNC_PREWRITE); ring->queued = 0; - ring->cur = ring->next = ring->stat = 0; + ring->cur = ring->stat = 0; } void @@ -881,6 +880,36 @@ rt2661_eeprom_read(struct rt2661_softc *sc, uint8_t ad } void +rt2661_free_tx_desc(struct rt2661_softc *sc, struct rt2661_tx_ring *txq) +{ + struct rt2661_tx_desc *desc = &txq->desc[txq->stat]; + struct rt2661_tx_data *data = &txq->data[txq->stat]; + struct ieee80211com *ic = &sc->sc_ic; + + bus_dmamap_sync(sc->sc_dmat, data->map, 0, + data->map->dm_mapsize, BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sc_dmat, data->map); + m_freem(data->m); + data->m = NULL; + + /* descriptor is no longer valid */ + desc->flags &= ~htole32(RT2661_TX_VALID); + + bus_dmamap_sync(sc->sc_dmat, txq->map, + txq->stat * RT2661_TX_DESC_SIZE, RT2661_TX_DESC_SIZE, + BUS_DMASYNC_PREWRITE); + + if (data->ni) { + ieee80211_release_node(ic, data->ni); + data->ni = NULL; + } + + txq->queued--; + if (++txq->stat >= txq->count) /* faster than % count */ + txq->stat = 0; +} + +void rt2661_tx_intr(struct rt2661_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; @@ -888,7 +917,7 @@ rt2661_tx_intr(struct rt2661_softc *sc) struct rt2661_tx_ring *txq; struct rt2661_tx_data *data; struct rt2661_node *rn; - int qid, retrycnt; + int qid, ind, retrycnt; for (;;) { const uint32_t val = RAL_READ(sc, RT2661_STA_CSR4); @@ -898,7 +927,14 @@ rt2661_tx_intr(struct rt2661_softc *sc) /* retrieve the queue in which this frame was sent */ qid = RT2661_TX_QID(val); txq = (qid <= 3) ? &sc->txq[qid] : &sc->mgtq; + ind = RT2661_TX_INDEX(val); + if (txq->stat != ind) + DPRINTFN(10, ("missed TX interrupt, catching up " + "stat %d to index %d\n", txq->stat, ind, qid)); + while (txq->stat != ind) + rt2661_free_tx_desc(sc, txq); + /* retrieve rate control algorithm context */ data = &txq->data[txq->stat]; rn = (struct rt2661_node *)data->ni; @@ -934,14 +970,9 @@ rt2661_tx_intr(struct rt2661_softc *sc) ifp->if_oerrors++; } - ieee80211_release_node(ic, data->ni); - data->ni = NULL; - DPRINTFN(15, ("tx done q=%d idx=%u\n", qid, txq->stat)); - txq->queued--; - if (++txq->stat >= txq->count) /* faster than % count */ - txq->stat = 0; + rt2661_free_tx_desc(sc, txq); } sc->sc_tx_timer = 0; @@ -950,42 +981,6 @@ rt2661_tx_intr(struct rt2661_softc *sc) } void -rt2661_tx_dma_intr(struct rt2661_softc *sc, struct rt2661_tx_ring *txq) -{ - for (;;) { - struct rt2661_tx_desc *desc = &txq->desc[txq->next]; - struct rt2661_tx_data *data = &txq->data[txq->next]; - - bus_dmamap_sync(sc->sc_dmat, txq->map, - txq->next * RT2661_TX_DESC_SIZE, RT2661_TX_DESC_SIZE, - BUS_DMASYNC_POSTREAD); - - if ((letoh32(desc->flags) & RT2661_TX_BUSY) || - !(letoh32(desc->flags) & RT2661_TX_VALID)) - break; - - bus_dmamap_sync(sc->sc_dmat, data->map, 0, - data->map->dm_mapsize, BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(sc->sc_dmat, data->map); - m_freem(data->m); - data->m = NULL; - /* node reference is released in rt2661_tx_intr() */ - - /* descriptor is no longer valid */ - desc->flags &= ~htole32(RT2661_TX_VALID); - - bus_dmamap_sync(sc->sc_dmat, txq->map, - txq->next * RT2661_TX_DESC_SIZE, RT2661_TX_DESC_SIZE, - BUS_DMASYNC_PREWRITE); - - DPRINTFN(15, ("tx dma done q=%p idx=%u\n", txq, txq->next)); - - if (++txq->next >= txq->count) /* faster than % count */ - txq->next = 0; - } -} - -void rt2661_rx_intr(struct rt2661_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; @@ -1212,24 +1207,9 @@ rt2661_intr(void *arg) if (!(ifp->if_flags & IFF_RUNNING)) return 0; - if (r1 & RT2661_MGT_DONE) - rt2661_tx_dma_intr(sc, &sc->mgtq); - if (r1 & RT2661_RX_DONE) rt2661_rx_intr(sc); - if (r1 & RT2661_TX0_DMA_DONE) - rt2661_tx_dma_intr(sc, &sc->txq[0]); - - if (r1 & RT2661_TX1_DMA_DONE) - rt2661_tx_dma_intr(sc, &sc->txq[1]); - - if (r1 & RT2661_TX2_DMA_DONE) - rt2661_tx_dma_intr(sc, &sc->txq[2]); - - if (r1 & RT2661_TX3_DMA_DONE) - rt2661_tx_dma_intr(sc, &sc->txq[3]); - if (r1 & RT2661_TX_DONE) rt2661_tx_intr(sc); @@ -1377,7 +1357,7 @@ rt2661_plcp_signal(int rate) void rt2661_setup_tx_desc(struct rt2661_softc *sc, struct rt2661_tx_desc *desc, uint32_t flags, uint16_t xflags, int len, int rate, - const bus_dma_segment_t *segs, int nsegs, int ac) + const bus_dma_segment_t *segs, int nsegs, int ac, int ind) { struct ieee80211com *ic = &sc->sc_ic; uint16_t plcp_length; @@ -1401,7 +1381,7 @@ rt2661_setup_tx_desc(struct rt2661_softc *sc, struct r * private data only. It will be made available by the NIC in STA_CSR4 * on Tx interrupts. */ - desc->qid = ac; + desc->qid = (ac <= 3 ? ac : 7) | (ind << 3); /* setup PLCP fields */ desc->plcp_signal = rt2661_plcp_signal(rate); @@ -1505,7 +1485,7 @@ rt2661_tx_mgt(struct rt2661_softc *sc, struct mbuf *m0 rt2661_setup_tx_desc(sc, desc, flags, 0 /* XXX HWSEQ */, m0->m_pkthdr.len, rate, data->map->dm_segs, data->map->dm_nsegs, - RT2661_QID_MGT); + RT2661_QID_MGT, sc->mgtq.cur); bus_dmamap_sync(sc->sc_dmat, data->map, 0, data->map->dm_mapsize, BUS_DMASYNC_PREWRITE); @@ -1633,7 +1613,7 @@ rt2661_tx_data(struct rt2661_softc *sc, struct mbuf *m rt2661_setup_tx_desc(sc, desc, (needrts ? RT2661_TX_NEED_ACK : 0) | RT2661_TX_MORE_FRAG, 0, mprot->m_pkthdr.len, protrate, data->map->dm_segs, - data->map->dm_nsegs, ac); + data->map->dm_nsegs, ac, txq->cur); bus_dmamap_sync(sc->sc_dmat, data->map, 0, data->map->dm_mapsize, BUS_DMASYNC_PREWRITE); @@ -1723,7 +1703,7 @@ rt2661_tx_data(struct rt2661_softc *sc, struct mbuf *m } rt2661_setup_tx_desc(sc, desc, flags, 0, m0->m_pkthdr.len, rate, - data->map->dm_segs, data->map->dm_nsegs, ac); + data->map->dm_segs, data->map->dm_nsegs, ac, txq->cur); bus_dmamap_sync(sc->sc_dmat, data->map, 0, data->map->dm_mapsize, BUS_DMASYNC_PREWRITE); @@ -2797,7 +2777,7 @@ rt2661_prepare_beacon(struct rt2661_softc *sc) rate = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? 12 : 2; rt2661_setup_tx_desc(sc, &desc, RT2661_TX_TIMESTAMP, RT2661_TX_HWSEQ, - m0->m_pkthdr.len, rate, NULL, 0, RT2661_QID_MGT); + m0->m_pkthdr.len, rate, NULL, 0, RT2661_QID_MGT, 0); /* copy the first 24 bytes of Tx descriptor into NIC memory */ RAL_WRITE_REGION_1(sc, RT2661_HW_BEACON_BASE0, (uint8_t *)&desc, 24); Index: rt2661reg.h =================================================================== RCS file: /cvs/src/sys/dev/ic/rt2661reg.h,v retrieving revision 1.10 diff -N -u -p rt2661reg.h --- rt2661reg.h 10 Aug 2009 18:13:17 -0000 1.10 +++ rt2661reg.h 28 Dec 2009 21:16:06 -0000 @@ -189,7 +189,8 @@ #define RT2661_TX_STAT_VALID (1 << 0) #define RT2661_TX_RESULT(v) (((v) >> 1) & 0x7) #define RT2661_TX_RETRYCNT(v) (((v) >> 4) & 0xf) -#define RT2661_TX_QID(v) (((v) >> 8) & 0xf) +#define RT2661_TX_QID(v) (((v) >> 8) & 0x7) +#define RT2661_TX_INDEX(v) (((v) >>11) & 0x1f) #define RT2661_TX_SUCCESS 0 #define RT2661_TX_RETRY_FAIL 6 Index: rt2661var.h =================================================================== RCS file: /cvs/src/sys/dev/ic/rt2661var.h,v retrieving revision 1.10 diff -N -u -p rt2661var.h --- rt2661var.h 10 Aug 2009 17:47:23 -0000 1.10 +++ rt2661var.h 28 Dec 2009 21:16:06 -0000 @@ -62,7 +62,6 @@ struct rt2661_tx_ring { int count; int queued; int cur; - int next; int stat; };