summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorwpaul <wpaul@FreeBSD.org>2001-02-22 19:26:55 +0000
committerwpaul <wpaul@FreeBSD.org>2001-02-22 19:26:55 +0000
commit10926b121d7a9505841e75788e3113e28939c569 (patch)
tree38aad0fc101e7023ce03ac46ce9d8de3dbdc4022 /sys/dev
parentaba557bd7c700da1854148971769566333eabb2c (diff)
downloadFreeBSD-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.c84
-rw-r--r--sys/dev/dc/if_dcreg.h6
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
/*
OpenPOWER on IntegriCloud