diff options
author | wpaul <wpaul@FreeBSD.org> | 2001-02-22 19:26:55 +0000 |
---|---|---|
committer | wpaul <wpaul@FreeBSD.org> | 2001-02-22 19:26:55 +0000 |
commit | 10926b121d7a9505841e75788e3113e28939c569 (patch) | |
tree | 38aad0fc101e7023ce03ac46ce9d8de3dbdc4022 /sys/dev | |
parent | aba557bd7c700da1854148971769566333eabb2c (diff) | |
download | FreeBSD-src-10926b121d7a9505841e75788e3113e28939c569.zip FreeBSD-src-10926b121d7a9505841e75788e3113e28939c569.tar.gz |
Apply patch to allow TX underrun handling without issuing a complete
chip reset. Just temporarily turn off the transmitter instead.
Submitted by: Stephen McKay <mckay@freebsd.org>
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/dc/if_dc.c | 84 | ||||
-rw-r--r-- | sys/dev/dc/if_dcreg.h | 6 |
2 files changed, 64 insertions, 26 deletions
diff --git a/sys/dev/dc/if_dc.c b/sys/dev/dc/if_dc.c index 22037d8..83eb65e 100644 --- a/sys/dev/dc/if_dc.c +++ b/sys/dev/dc/if_dc.c @@ -203,6 +203,7 @@ static int dc_rx_resync __P((struct dc_softc *)); static void dc_rxeof __P((struct dc_softc *)); static void dc_txeof __P((struct dc_softc *)); static void dc_tick __P((void *)); +static void dc_tx_underrun __P((struct dc_softc *)); static void dc_intr __P((void *)); static void dc_start __P((struct ifnet *)); static int dc_ioctl __P((struct ifnet *, u_long, caddr_t)); @@ -1317,17 +1318,16 @@ static void dc_setcfg(sc, media) DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_TX_ON|DC_NETCFG_RX_ON)); for (i = 0; i < DC_TIMEOUT; i++) { - DELAY(10); isr = CSR_READ_4(sc, DC_ISR); - if (isr & DC_ISR_TX_IDLE || + if (isr & DC_ISR_TX_IDLE && (isr & DC_ISR_RX_STATE) == DC_RXSTATE_STOPPED) break; + DELAY(10); } if (i == DC_TIMEOUT) printf("dc%d: failed to force tx and " "rx to idle state\n", sc->dc_unit); - } if (IFM_SUBTYPE(media) == IFM_100_TX) { @@ -2705,6 +2705,57 @@ static void dc_tick(xsc) return; } +/* + * A transmit underrun has occurred. Back off the transmit threshold, + * or switch to store and forward mode if we have to. + */ +static void dc_tx_underrun(sc) + struct dc_softc *sc; +{ + u_int32_t isr; + int i; + + if (DC_IS_DAVICOM(sc)) + dc_init(sc); + + if (DC_IS_INTEL(sc)) { + /* + * The real 21143 requires that the transmitter be idle + * in order to change the transmit threshold or store + * and forward state. + */ + DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON); + + for (i = 0; i < DC_TIMEOUT; i++) { + isr = CSR_READ_4(sc, DC_ISR); + if (isr & DC_ISR_TX_IDLE) + break; + DELAY(10); + } + if (i == DC_TIMEOUT) { + printf("dc%d: failed to force tx to idle state\n", + sc->dc_unit); + dc_init(sc); + } + } + + printf("dc%d: TX underrun -- ", sc->dc_unit); + sc->dc_txthresh += DC_TXTHRESH_INC; + if (sc->dc_txthresh > DC_TXTHRESH_MAX) { + printf("using store and forward mode\n"); + DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD); + } else { + printf("increasing TX threshold\n"); + DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_TX_THRESH); + DC_SETBIT(sc, DC_NETCFG, sc->dc_txthresh); + } + + if (DC_IS_INTEL(sc)) + DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON); + + return; +} + static void dc_intr(arg) void *arg; { @@ -2757,27 +2808,8 @@ static void dc_intr(arg) } } - if (status & DC_ISR_TX_UNDERRUN) { - u_int32_t cfg; - - printf("dc%d: TX underrun -- ", sc->dc_unit); - if (DC_IS_DAVICOM(sc) || DC_IS_INTEL(sc)) - dc_init(sc); - cfg = CSR_READ_4(sc, DC_NETCFG); - cfg &= ~DC_NETCFG_TX_THRESH; - if (sc->dc_txthresh == DC_TXTHRESH_160BYTES) { - printf("using store and forward mode\n"); - DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD); - } else if (sc->dc_flags & DC_TX_STORENFWD) { - printf("resetting\n"); - } else { - sc->dc_txthresh += 0x4000; - printf("increasing TX threshold\n"); - CSR_WRITE_4(sc, DC_NETCFG, cfg); - DC_SETBIT(sc, DC_NETCFG, sc->dc_txthresh); - DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD); - } - } + if (status & DC_ISR_TX_UNDERRUN) + dc_tx_underrun(sc); if ((status & DC_ISR_RX_WATDOGTIMEO) || (status & DC_ISR_RX_NOBUF)) { @@ -3031,7 +3063,7 @@ static void dc_init(xsc) if (sc->dc_flags & DC_TX_STORENFWD) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD); else { - if (sc->dc_txthresh == DC_TXTHRESH_160BYTES) { + if (sc->dc_txthresh > DC_TXTHRESH_MAX) { DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD); } else { DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD); @@ -3072,7 +3104,7 @@ static void dc_init(xsc) } DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_TX_THRESH); - DC_SETBIT(sc, DC_NETCFG, DC_TXTHRESH_72BYTES); + DC_SETBIT(sc, DC_NETCFG, DC_TXTHRESH_MIN); /* Init circular RX list. */ if (dc_list_rx_init(sc) == ENOBUFS) { diff --git a/sys/dev/dc/if_dcreg.h b/sys/dev/dc/if_dcreg.h index 56f441f..658b221 100644 --- a/sys/dev/dc/if_dcreg.h +++ b/sys/dev/dc/if_dcreg.h @@ -220,10 +220,16 @@ #define DC_OPMODE_INTLOOP 0x00000400 #define DC_OPMODE_EXTLOOP 0x00000800 +#if 0 #define DC_TXTHRESH_72BYTES 0x00000000 #define DC_TXTHRESH_96BYTES 0x00004000 #define DC_TXTHRESH_128BYTES 0x00008000 #define DC_TXTHRESH_160BYTES 0x0000C000 +#endif + +#define DC_TXTHRESH_MIN 0x00000000 +#define DC_TXTHRESH_INC 0x00004000 +#define DC_TXTHRESH_MAX 0x0000C000 /* |