diff options
| author | Marius Strobl <marius@FreeBSD.org> | 2006-02-21 20:20:43 +0000 |
|---|---|---|
| committer | Marius Strobl <marius@FreeBSD.org> | 2006-02-21 20:20:43 +0000 |
| commit | 0c05ab41ab49810945b69e861df3bf3ac9e13308 (patch) | |
| tree | 2e39817b4a0c8db6c3b907c814975bb7f547f5b7 /sys/dev/le | |
| parent | 65986ff98dfea5e24e2a29bbda4dcc98de8ef043 (diff) | |
Notes
Diffstat (limited to 'sys/dev/le')
| -rw-r--r-- | sys/dev/le/am7990.c | 41 | ||||
| -rw-r--r-- | sys/dev/le/am79900.c | 41 |
2 files changed, 48 insertions, 34 deletions
diff --git a/sys/dev/le/am7990.c b/sys/dev/le/am7990.c index b626ce9d6867..f45a48d8e1ef 100644 --- a/sys/dev/le/am7990.c +++ b/sys/dev/le/am7990.c @@ -357,10 +357,7 @@ am7990_tint(struct lance_softc *sc) sc->sc_first_td = bix; - am7990_start_locked(sc); - - if (sc->sc_no_td == 0) - ifp->if_timer = 0; + ifp->if_timer = sc->sc_no_td > 0 ? 5 : 0; } /* @@ -392,6 +389,18 @@ am7990_intr(void *arg) return; } + /* + * Clear interrupt source flags and turn off interrupts. If we + * don't clear these flags before processing their sources we + * could completely miss some interrupt events as the the NIC + * can change these flags while we're in this handler. We turn + * of interrupts while processing them so we don't get another + * one while we still process the previous one in ifp->if_input() + * with the driver lock dropped. + */ + (*sc->sc_wrcsr)(sc, LE_CSR0, isr & ~(LE_C0_INEA | LE_C0_TDMD | + LE_C0_STOP | LE_C0_STRT | LE_C0_INIT)); + if (isr & LE_C0_ERR) { if (isr & LE_C0_BABL) { #ifdef LEDEBUG @@ -446,16 +455,11 @@ am7990_intr(void *arg) if (isr & LE_C0_TINT) am7990_tint(sc); - /* - * Note that since we drop the driver lock in lance_read() we might - * get another interrupt while in ifp->if_input(). Consequently we - * don't want to acknowledge a receive interrupt before it's fully - * serviced. We could acknowledge interrupts of other types earlier - * but that won't buy us much as as the driver lock is held until - * the end of this ISR. - */ - (*sc->sc_wrcsr)(sc, LE_CSR0, isr & (LE_C0_INEA | LE_C0_BABL | - LE_C0_MISS | LE_C0_MERR | LE_C0_RINT | LE_C0_TINT | LE_C0_IDON)); + /* Enable interrupts again. */ + (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA); + + if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + am7990_start_locked(sc); LE_UNLOCK(sc); } @@ -471,7 +475,7 @@ am7990_start_locked(struct lance_softc *sc) struct ifnet *ifp = sc->sc_ifp; struct letmd tmd; struct mbuf *m; - int bix, len, rp; + int bix, enq, len, rp; LE_LOCK_ASSERT(sc, MA_OWNED); @@ -480,6 +484,7 @@ am7990_start_locked(struct lance_softc *sc) return; bix = sc->sc_last_td; + enq = 0; for (; sc->sc_no_td < sc->sc_ntbuf && !IFQ_DRV_IS_EMPTY(&ifp->if_snd);) { @@ -513,8 +518,6 @@ am7990_start_locked(struct lance_softc *sc) if_printf(ifp, "packet length %d\n", len); #endif - ifp->if_timer = 5; - /* * Init transmit registers, and set transmit start flag. */ @@ -530,6 +533,7 @@ am7990_start_locked(struct lance_softc *sc) #endif (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_TDMD); + enq++; if (++bix == sc->sc_ntbuf) bix = 0; @@ -541,6 +545,9 @@ am7990_start_locked(struct lance_softc *sc) } sc->sc_last_td = bix; + + if (enq > 0) + ifp->if_timer = 5; } #ifdef LEDEBUG diff --git a/sys/dev/le/am79900.c b/sys/dev/le/am79900.c index 356c83c7f82e..09f604aa2e98 100644 --- a/sys/dev/le/am79900.c +++ b/sys/dev/le/am79900.c @@ -399,10 +399,7 @@ am79900_tint(struct lance_softc *sc) sc->sc_first_td = bix; - am79900_start_locked(sc); - - if (sc->sc_no_td == 0) - ifp->if_timer = 0; + ifp->if_timer = sc->sc_no_td > 0 ? 5 : 0; } /* @@ -434,6 +431,18 @@ am79900_intr(void *arg) return; } + /* + * Clear interrupt source flags and turn off interrupts. If we + * don't clear these flags before processing their sources we + * could completely miss some interrupt events as the the NIC + * can change these flags while we're in this handler. We turn + * of interrupts while processing them so we don't get another + * one while we still process the previous one in ifp->if_input() + * with the driver lock dropped. + */ + (*sc->sc_wrcsr)(sc, LE_CSR0, isr & ~(LE_C0_INEA | LE_C0_TDMD | + LE_C0_STOP | LE_C0_STRT | LE_C0_INIT)); + if (isr & LE_C0_ERR) { if (isr & LE_C0_BABL) { #ifdef LEDEBUG @@ -488,16 +497,11 @@ am79900_intr(void *arg) if (isr & LE_C0_TINT) am79900_tint(sc); - /* - * Note that since we drop the driver lock in lance_read() we might - * get another interrupt while in ifp->if_input(). Consequently we - * don't want to acknowledge a receive interrupt before it's fully - * serviced. We could acknowledge interrupts of other types earlier - * but that won't buy us much as as the driver lock is held until - * the end of this ISR. - */ - (*sc->sc_wrcsr)(sc, LE_CSR0, isr & (LE_C0_INEA | LE_C0_BABL | - LE_C0_MISS | LE_C0_MERR | LE_C0_RINT | LE_C0_TINT | LE_C0_IDON)); + /* Enable interrupts again. */ + (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA); + + if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + am79900_start_locked(sc); LE_UNLOCK(sc); } @@ -513,7 +517,7 @@ am79900_start_locked(struct lance_softc *sc) struct ifnet *ifp = sc->sc_ifp; struct letmd tmd; struct mbuf *m; - int bix, len, rp; + int bix, enq, len, rp; LE_LOCK_ASSERT(sc, MA_OWNED); @@ -522,6 +526,7 @@ am79900_start_locked(struct lance_softc *sc) return; bix = sc->sc_last_td; + enq = 0; for (; sc->sc_no_td < sc->sc_ntbuf && !IFQ_DRV_IS_EMPTY(&ifp->if_snd);) { @@ -555,8 +560,6 @@ am79900_start_locked(struct lance_softc *sc) if_printf(ifp, "packet length %d\n", len); #endif - ifp->if_timer = 5; - /* * Init transmit registers, and set transmit start flag. */ @@ -573,6 +576,7 @@ am79900_start_locked(struct lance_softc *sc) #endif (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_TDMD); + enq++; if (++bix == sc->sc_ntbuf) bix = 0; @@ -584,6 +588,9 @@ am79900_start_locked(struct lance_softc *sc) } sc->sc_last_td = bix; + + if (enq > 0) + ifp->if_timer = 5; } #ifdef LEDEBUG |
