summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorBrad Smith <brad@cvs.openbsd.org>2004-10-14 15:34:29 +0000
committerBrad Smith <brad@cvs.openbsd.org>2004-10-14 15:34:29 +0000
commit4515eb88c089111edf2ffba839ccd08b6db75b87 (patch)
tree662f5f68bbc079a10d6bb2ea4a6b7f2702302290 /sys
parent8e6b36fe4efd197b88161ee0840b9545fec5fae4 (diff)
rev 1.47
Add a check in the interrupt service routine to return quickly in case there is nothing to do. This happens normally when the card shares the interrupt line with other devices. This code saves a couple of microseconds per interrupt even on a fast CPU. You normally would not care, except under heavy tinygram traffic where you can have some 50-100.000 interrupts per second... rev 1.51 Patch to allow TX underrun handling without issuing a complete chip reset. Just temporarily turn off the transmitter instead. From FreeBSD ok mcbride@ tested by mcbride@, jaredy@, marco@, grange@, <harding at motd dot ca>
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/ic/dc.c83
1 files changed, 60 insertions, 23 deletions
diff --git a/sys/dev/ic/dc.c b/sys/dev/ic/dc.c
index 430212c3905..4f1922d9aea 100644
--- a/sys/dev/ic/dc.c
+++ b/sys/dev/ic/dc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dc.c,v 1.71 2004/10/06 17:02:47 brad Exp $ */
+/* $OpenBSD: dc.c,v 1.72 2004/10/14 15:34:28 brad Exp $ */
/*
* Copyright (c) 1997, 1998, 1999
@@ -142,6 +142,7 @@ int dc_rx_resync(struct dc_softc *);
void dc_rxeof(struct dc_softc *);
void dc_txeof(struct dc_softc *);
void dc_tick(void *);
+void dc_tx_underrun(struct dc_softc *);
void dc_start(struct ifnet *);
int dc_ioctl(struct ifnet *, u_long, caddr_t);
void dc_init(void *);
@@ -1229,17 +1230,16 @@ 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("%s: failed to force tx and "
"rx to idle state\n", sc->sc_dev.dv_xname);
-
}
if (IFM_SUBTYPE(media) == IFM_100_TX) {
@@ -2406,6 +2406,54 @@ dc_tick(xsc)
splx(s);
}
+/* A transmit underrun has occurred. Back off the transmit threshold,
+ * or switch to store and forward mode if we have to.
+ */
+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("%s: failed to force tx to idle state\n",
+ sc->sc_dev.dv_xname);
+ dc_init(sc);
+ }
+ }
+
+ sc->dc_txthresh += DC_TXTHRESH_INC;
+ if (sc->dc_txthresh > DC_TXTHRESH_MAX) {
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD);
+ } else {
+ 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;
+}
+
int
dc_intr(arg)
void *arg;
@@ -2416,6 +2464,10 @@ dc_intr(arg)
int claimed = 0;
sc = arg;
+
+ if ( (CSR_READ_4(sc, DC_ISR) & DC_INTRS) == 0)
+ return (0);
+
ifp = &sc->sc_arpcom.ac_if;
/* Suppress unwanted interrupts */
@@ -2455,23 +2507,8 @@ dc_intr(arg)
}
}
- if (status & DC_ISR_TX_UNDERRUN) {
- u_int32_t cfg;
-
- 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) {
- DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD);
- } else if (sc->dc_flags & DC_TX_STORENFWD) {
- } else {
- sc->dc_txthresh += 0x4000;
- 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)) {
@@ -2761,7 +2798,7 @@ 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);
@@ -2798,7 +2835,7 @@ 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) {