If we get a TX interrupt with no packets buffered, ignore it. This can occur

if the chip is reset while transmitting.

XXX
This occurs at boot time because the SIOCADDMULTI always resets the interface
when adding the `all hosts groups' -- usually while the ARP packet is being
transmitted.  All drivers should be fixed to not reset the interface when
changing the multicast filter, if possible.
This commit is contained in:
mycroft 1998-11-12 13:18:26 +00:00
parent b8974fbf40
commit 8146c925da

View File

@ -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);
}