diff options
author | gallatin <gallatin@FreeBSD.org> | 2000-07-19 14:33:52 +0000 |
---|---|---|
committer | gallatin <gallatin@FreeBSD.org> | 2000-07-19 14:33:52 +0000 |
commit | b0e74737e90dd9a2b77a103978f5e4bfa63edf17 (patch) | |
tree | 020cc7532b087697dfe2e6d328cf556bdeb51d08 /sys/dev/fxp | |
parent | 9f3624548b71b3532a679d6cedf8b009eae2f3f4 (diff) | |
download | FreeBSD-src-b0e74737e90dd9a2b77a103978f5e4bfa63edf17.zip FreeBSD-src-b0e74737e90dd9a2b77a103978f5e4bfa63edf17.tar.gz |
Fix an alpha-only race which causes the transmit side of the chip to
lock up under moderate to heavy load.
The status & command fields share a 32-bit longword. The programming
API of the eepro apparently requires that you update the command field
of a transmit slot that you've already given to the card. This means
the card could be updating the status field of the same longword at
the same time. Since alphas can only operate on 32-bit chunks of
memory, both the status & command fields are loaded from memory &
operated on in registers when the following line of C is executed:
sc->cbl_last->cb_command &= ~FXP_CB_COMMAND_S;
The race is caused by the card DMA'ing up the status at just the wrong
time -- after it has been loaded into a register & before it has been
written back. The old value of the status is written back, clobbering
the status the card just DMA'ed up. The fact that the card has sent
this frame is missed & the transmit engine appears to hang.
Luckily, as numerous people on the freebsd-alpha list pointed out, the
load-locked/store-conditional instructions used by the atomic
functions work with respect changes in memory due to I/O devices. We
now use them to safely update the command field.
Tested by: Bernd Walter <ticso@mail.cicely.de>
Diffstat (limited to 'sys/dev/fxp')
-rw-r--r-- | sys/dev/fxp/if_fxp.c | 12 |
1 files changed, 12 insertions, 0 deletions
diff --git a/sys/dev/fxp/if_fxp.c b/sys/dev/fxp/if_fxp.c index 408ec5d..e86abad 100644 --- a/sys/dev/fxp/if_fxp.c +++ b/sys/dev/fxp/if_fxp.c @@ -1053,7 +1053,19 @@ tbdinit: /* * Advance the end of list forward. */ + +#ifdef __alpha__ + /* + * On platforms which can't access memory in 16-bit + * granularities, we must prevent the card from DMA'ing + * up the status while we update the command field. + * This could cause us to overwrite the completion status. + */ + atomic_clear_short(&sc->cbl_last->cb_command, + FXP_CB_COMMAND_S); +#else sc->cbl_last->cb_command &= ~FXP_CB_COMMAND_S; +#endif /*__alpha__*/ sc->cbl_last = txp; /* |