diff options
author | Brad Smith <brad@cvs.openbsd.org> | 2006-06-15 20:12:41 +0000 |
---|---|---|
committer | Brad Smith <brad@cvs.openbsd.org> | 2006-06-15 20:12:41 +0000 |
commit | 7b21556daf0a60db3098be08138be972cfec1429 (patch) | |
tree | b032f30deff00bcb7f62ea3d32f55fc75f4bf3cb /sys/dev | |
parent | 3c18738eebc3ab152ffb51145446e53abd3236d3 (diff) |
Fix watchdog timeout errors seen on a few systems.
The SK-NET GENESIS document says reading the SK_ISSR register should stop
generating further interrupts, but it seems there is the possibility
of losing interrupts between reading the SK_ISSR register and determining
which interrupts have been reported. To cope with this situation we
continuously read the SK_ISSR register until there are no interrupts.
However, it seems that the above workaround does not fix all cases.
Add workaround code that tries to protect against false alarms from
the watchdog handler by trying to reclaim pending Tx descriptors
before resetting the hardware.
This should fix occasional watchdog timeouts seen with this driver.
From FreeBSD
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/if_sk.c | 19 |
1 files changed, 13 insertions, 6 deletions
diff --git a/sys/dev/pci/if_sk.c b/sys/dev/pci/if_sk.c index d3aad1102b4..921086a9212 100644 --- a/sys/dev/pci/if_sk.c +++ b/sys/dev/pci/if_sk.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_sk.c,v 1.111 2006/05/28 00:20:21 brad Exp $ */ +/* $OpenBSD: if_sk.c,v 1.112 2006/06/15 20:12:40 brad Exp $ */ /* * Copyright (c) 1997, 1998, 1999, 2000 @@ -1821,11 +1821,18 @@ sk_watchdog(struct ifnet *ifp) { struct sk_if_softc *sc_if = ifp->if_softc; - printf("%s: watchdog timeout\n", sc_if->sk_dev.dv_xname); + /* + * Reclaim first as there is a possibility of losing Tx completion + * interrupts. + */ + sk_txeof(sc_if); + if (sc_if->sk_cdata.sk_tx_cnt != 0) { + printf("%s: watchdog timeout\n", sc_if->sk_dev.dv_xname); - ifp->if_oerrors++; + ifp->if_oerrors++; - sk_init(sc_if); + sk_init(sc_if); + } } void @@ -2247,8 +2254,7 @@ sk_intr(void *xsc) if (sc_if1 != NULL) ifp1 = &sc_if1->arpcom.ac_if; - status &= sc->sk_intrmask; - if ((status & sc->sk_intrmask) != 0) { + for (; (status &= sc->sk_intrmask) != 0;) { claimed = 1; /* Handle receive interrupts first. */ @@ -2302,6 +2308,7 @@ sk_intr(void *xsc) sc_if1->sk_phytype == SK_PHYTYPE_BCOM) sk_intr_bcom(sc_if1); } + status = CSR_READ_4(sc, SK_ISSR); } CSR_WRITE_4(sc, SK_IMR, sc->sk_intrmask); |