diff --git a/sys/dev/ic/dp8390.c b/sys/dev/ic/dp8390.c index cd461a17ca30..d9f066480e5d 100644 --- a/sys/dev/ic/dp8390.c +++ b/sys/dev/ic/dp8390.c @@ -1,4 +1,4 @@ -/* $NetBSD: dp8390.c,v 1.13 1998/07/05 06:49:11 jonathan Exp $ */ +/* $NetBSD: dp8390.c,v 1.14 1998/11/12 13:18:26 mycroft Exp $ */ /* * Device driver for National Semiconductor DS8390/WD83C690 based ethernet @@ -305,12 +305,6 @@ dp8390_init(sc) NIC_PUT(regt, regh, ED_P0_PSTART, sc->rec_page_start); NIC_PUT(regt, regh, ED_P0_PSTOP, sc->rec_page_stop); - /* - * Clear all interrupts. A '1' in each bit position clears the - * corresponding flag. - */ - NIC_PUT(regt, regh, ED_P0_ISR, 0xff); - /* * Enable the following interrupts: receive/transmit complete, * receive/transmit error, and Receiver OverWrite. @@ -321,6 +315,12 @@ dp8390_init(sc) ED_IMR_PRXE | ED_IMR_PTXE | ED_IMR_RXEE | ED_IMR_TXEE | ED_IMR_OVWE); + /* + * Clear all interrupts. A '1' in each bit position clears the + * corresponding flag. + */ + NIC_PUT(regt, regh, ED_P0_ISR, 0xff); + /* Program command register for page 1. */ NIC_PUT(regt, regh, ED_P0_CR, sc->cr_proto | ED_CR_PAGE_1 | ED_CR_STP); @@ -346,6 +346,7 @@ dp8390_init(sc) NIC_PUT(regt, regh, ED_P1_CR, sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STP); + /* Accept broadcast and multicast packets by default. */ i = ED_RCR_AB | ED_RCR_AM; if (ifp->if_flags & IFF_PROMISC) { /* @@ -387,6 +388,15 @@ dp8390_xmit(sc) struct ifnet *ifp = &sc->sc_ec.ec_if; u_short len; +#ifdef DIAGNOSTIC + if ((sc->txb_next_tx + sc->txb_inuse) % sc->txb_cnt != sc->txb_new) + panic("dp8390_xmit: desync, next_tx=%d inuse=%d cnt=%d new=%d", + sc->txb_next_tx, sc->txb_inuse, sc->txb_cnt, sc->txb_new); + + if (sc->txb_inuse == 0) + panic("dp8390_xmit: no packets to xmit\n"); +#endif + len = sc->txb_len[sc->txb_next_tx]; /* Set NIC for page 0 register access. */ @@ -406,8 +416,7 @@ dp8390_xmit(sc) sc->cr_proto | ED_CR_PAGE_0 | ED_CR_TXP | ED_CR_STA); /* Point to next transmit buffer slot and wrap if necessary. */ - sc->txb_next_tx++; - if (sc->txb_next_tx == sc->txb_cnt) + if (++sc->txb_next_tx == sc->txb_cnt) sc->txb_next_tx = 0; /* Set a timer just in case we never hear from the board again. */ @@ -468,15 +477,13 @@ outloop: m_freem(m0); sc->txb_len[sc->txb_new] = max(len, ETHER_MIN_LEN); - /* Start the first packet transmitting. */ - if (sc->txb_inuse == 0) - dp8390_xmit(sc); - /* Point to next buffer slot and wrap if necessary. */ if (++sc->txb_new == sc->txb_cnt) sc->txb_new = 0; - sc->txb_inuse++; + /* Start the first packet transmitting. */ + if (sc->txb_inuse++ == 0) + dp8390_xmit(sc); /* Loop back to the top to possibly buffer more packets. */ goto outloop; @@ -634,10 +641,15 @@ dp8390_intr(arg) /* * Handle transmitter interrupts. Handle these first because * the receiver will reset the board under some conditions. + * + * If the chip was reset while a packet was transmitting, it + * may still deliver a TX interrupt. In this case, just ignore + * the interrupt. */ - if (isr & (ED_ISR_PTX | ED_ISR_TXE)) { - u_char collisions = NIC_GET(regt, regh, - ED_P0_NCR) & 0x0f; + if (isr & (ED_ISR_PTX | ED_ISR_TXE) && + sc->txb_inuse != 0) { + u_char collisions = + NIC_GET(regt, regh, ED_P0_NCR) & 0x0f; /* * Check for transmit error. If a TX completed with an @@ -648,7 +660,6 @@ dp8390_intr(arg) * course, with UDP we're screwed, but this is expected * when a network is heavily loaded. */ - (void)NIC_GET(regt, regh, ED_P0_TSR); if (isr & ED_ISR_TXE) { /* * Excessive collisions (16). @@ -666,6 +677,15 @@ dp8390_intr(arg) /* Update output errors counter. */ ++ifp->if_oerrors; } else { + /* + * Throw away the non-error status bits. + * + * XXX + * It may be useful to detect loss of carrier + * and late collisions here. + */ + (void)NIC_GET(regt, regh, ED_P0_TSR); + /* * Update total number of successfully * transmitted packets. @@ -673,9 +693,6 @@ dp8390_intr(arg) ++ifp->if_opackets; } - /* Done with the buffer. */ - sc->txb_inuse--; - /* Clear watchdog timer. */ ifp->if_timer = 0; ifp->if_flags &= ~IFF_OACTIVE; @@ -693,7 +710,7 @@ dp8390_intr(arg) * If data is ready to transmit, start it transmitting, * otherwise defer until after handling receiver. */ - if (sc->txb_inuse > 0) + if (--sc->txb_inuse != 0) dp8390_xmit(sc); }