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:
parent
b8974fbf40
commit
8146c925da
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user