diff options
author | imp <imp@FreeBSD.org> | 2001-11-24 16:15:18 +0000 |
---|---|---|
committer | imp <imp@FreeBSD.org> | 2001-11-24 16:15:18 +0000 |
commit | 55262e3b08db9fbbce5c1b2e4d8622e44a7e9bbe (patch) | |
tree | dbd8cf8ecadcdde2c6a23463b1607228bdec5a4e /sys/dev/ed | |
parent | bd8e2fa8eb0aecc989fbcb9a365735f5f935a1ee (diff) | |
download | FreeBSD-src-55262e3b08db9fbbce5c1b2e4d8622e44a7e9bbe.zip FreeBSD-src-55262e3b08db9fbbce5c1b2e4d8622e44a7e9bbe.tar.gz |
Patch to allow the ed driver interrupt routine to terminate if the
card is ejected while we're in this routine.
yamamoto-san's original patch had a small race window for AX88190
chips, which I corrected by limiting the number of iterations we'd try
to reset the bits to be about 15ms rather than forever. This seems to
work for me, but I don't have a large collections of cards based on
this chipset.
Submitted by: YAMAMOTO Shigeru
Diffstat (limited to 'sys/dev/ed')
-rw-r--r-- | sys/dev/ed/if_ed.c | 21 |
1 files changed, 17 insertions, 4 deletions
diff --git a/sys/dev/ed/if_ed.c b/sys/dev/ed/if_ed.c index 43099ef..8fb2dc8 100644 --- a/sys/dev/ed/if_ed.c +++ b/sys/dev/ed/if_ed.c @@ -2285,6 +2285,7 @@ edintr(arg) struct ed_softc *sc = (struct ed_softc*) arg; struct ifnet *ifp = (struct ifnet *)sc; u_char isr; + int count; if (sc->gone) return; @@ -2294,9 +2295,12 @@ edintr(arg) ed_nic_outb(sc, ED_P0_CR, sc->cr_proto | ED_CR_STA); /* - * loop until there are no more new interrupts + * loop until there are no more new interrupts. When the card + * goes away, the hardware will read back 0xff. Looking at + * the interrupts, it would appear that 0xff is impossible, + * or at least extremely unlikely. */ - while ((isr = ed_nic_inb(sc, ED_P0_ISR)) != 0) { + while ((isr = ed_nic_inb(sc, ED_P0_ISR)) != 0 && isr != 0xff) { /* * reset all the bits that we are 'acknowledging' by writing a @@ -2305,12 +2309,21 @@ edintr(arg) */ ed_nic_outb(sc, ED_P0_ISR, isr); - /* XXX workaround for AX88190 */ + /* + * XXX workaround for AX88190 + * We limit this to 5000 iterations. At 1us per inb/outb, + * this translates to about 15ms, which should be plenty + * of time, and also gives protection in the card eject + * case. + */ if (sc->chip_type == ED_CHIP_TYPE_AX88190) { - while (ed_nic_inb(sc, ED_P0_ISR) & isr) { + count = 5000; /* 15ms */ + while (count-- && (ed_nic_inb(sc, ED_P0_ISR) & isr)) { ed_nic_outb(sc, ED_P0_ISR,0); ed_nic_outb(sc, ED_P0_ISR,isr); } + if (count == 0) + break; } /* |