i wrote this diff blind, so it may not compile or work. the intention is to check for space before attempting to dequeue a packet. the rest is largely cosmetic and makes it look more like a decent driver.
could someone test please? Index: sxie.c =================================================================== RCS file: /cvs/src/sys/arch/armv7/sunxi/sxie.c,v retrieving revision 1.25 diff -u -p -r1.25 sxie.c --- sxie.c 22 Jan 2017 10:17:37 -0000 1.25 +++ sxie.c 31 May 2017 07:08:55 -0000 @@ -439,16 +439,15 @@ sxie_intr(void *arg) } if (pending & (SXIE_TX_FIFO0 | SXIE_TX_FIFO1)) { - ifq_clr_oactive(&ifp->if_snd); sc->txf_inuse &= ~pending; if (sc->txf_inuse == 0) ifp->if_timer = 0; else ifp->if_timer = 5; - } - if (ifp->if_flags & IFF_RUNNING && !IFQ_IS_EMPTY(&ifp->if_snd)) - sxie_start(ifp); + if (ifq_is_oactive(&ifp->if_snd)) + ifq_restart(&ifp->if_snd); + } SXISET4(sc, SXIE_INTCR, SXIE_INTR_ENABLE); @@ -468,65 +467,59 @@ sxie_start(struct ifnet *ifp) uint32_t fifo; uint32_t txbuf[SXIE_MAX_PKT_SIZE / sizeof(uint32_t)]; /* XXX !!! */ - if (sc->txf_inuse == (SXIE_TX_FIFO0 | SXIE_TX_FIFO1)) - ifq_set_oactive(&ifp->if_snd); - if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd)) return; + td = (uint8_t *)&txbuf[0]; m = NULL; head = NULL; -trynext: - m = ifq_deq_begin(&ifp->if_snd); - if (m == NULL) - return; - - if (m->m_pkthdr.len > SXIE_MAX_PKT_SIZE) { - ifq_deq_commit(&ifp->if_snd, m); - printf("sxie_start: packet too big\n"); - m_freem(m); - return; - } - if (sc->txf_inuse == (SXIE_TX_FIFO0 | SXIE_TX_FIFO1)) { - ifq_deq_rollback(&ifp->if_snd, m); - printf("sxie_start: tx fifos in use.\n"); - ifq_set_oactive(&ifp->if_snd); - return; - } - - /* select fifo */ - if (sc->txf_inuse & SXIE_TX_FIFO0) { - sc->txf_inuse |= SXIE_TX_FIFO1; - fifo = 1; - } else { - sc->txf_inuse |= SXIE_TX_FIFO0; - fifo = 0; - } - SXIWRITE4(sc, SXIE_TXINS, fifo); - - /* set packet length */ - SXIWRITE4(sc, SXIE_TXPKTLEN0 + (fifo * 4), m->m_pkthdr.len); - - /* copy the actual packet to fifo XXX through 'align buffer'.. */ - m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)td); - bus_space_write_multi_4(sc->sc_iot, sc->sc_ioh, - SXIE_TXIO0 + (fifo * 4), - (uint32_t *)td, SXIE_ROUNDUP(m->m_pkthdr.len, 4) >> 2); - - /* transmit to PHY from fifo */ - SXISET4(sc, SXIE_TXCR0 + (fifo * 4), 1); - ifp->if_timer = 5; - ifq_deq_commit(&ifp->if_snd, m); + for (;;) { + if (sc->txf_inuse == (SXIE_TX_FIFO0 | SXIE_TX_FIFO1)) { + ifq_set_oactive(&ifp->if_snd); + break; + } + + m = ifq_dequeue(&ifp->if_snd); + if (m == NULL) + break; + + if (m->m_pkthdr.len > SXIE_MAX_PKT_SIZE) { + m_freem(m); + continue; + } #if NBPFILTER > 0 - if (ifp->if_bpf) - bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); #endif - m_freem(m); - goto trynext; + /* select fifo */ + if (sc->txf_inuse & SXIE_TX_FIFO0) { + sc->txf_inuse |= SXIE_TX_FIFO1; + fifo = 1; + } else { + sc->txf_inuse |= SXIE_TX_FIFO0; + fifo = 0; + } + SXIWRITE4(sc, SXIE_TXINS, fifo); + + /* set packet length */ + SXIWRITE4(sc, SXIE_TXPKTLEN0 + (fifo * 4), m->m_pkthdr.len); + + /* copy the actual packet to fifo XXX through 'align buffer' */ + m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)td); + bus_space_write_multi_4(sc->sc_iot, sc->sc_ioh, + SXIE_TXIO0 + (fifo * 4), + (uint32_t *)td, SXIE_ROUNDUP(m->m_pkthdr.len, 4) >> 2); + + /* transmit to PHY from fifo */ + SXISET4(sc, SXIE_TXCR0 + (fifo * 4), 1); + ifp->if_timer = 5; + + m_freem(m); + } } void