Make the members of the descriptors volatile, because the NIC and

the host share them.

Before breaking out of the loop over descriptors in gem_rint(),
DMA-resynchronize the first Rx descriptor we found that does not
belong to the host.  We must avoid a cached descriptor "covering"
a descriptor in RAM, because the cached descriptor may say that
the descriptor still belongs to the NIC, when that is not true,
and the driver will hang.

XXX I believe this driver only works by luck on hosts that both
XXX have a cacheline size greater than the size of a descriptor
XXX (16 bytes) and lack DMA/cache coherency.  I need to add some
XXX trickery to make sure that we don't scribble over the NIC's
XXX changes to a descriptor when we flush a cached descriptor to
XXX RAM with bus_dmamap_sync(9).
This commit is contained in:
dyoung 2007-04-12 06:14:40 +00:00
parent 7898b5e0a8
commit b7dea03346
2 changed files with 6 additions and 5 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: gem.c,v 1.55 2007/04/12 05:56:01 dyoung Exp $ */
/* $NetBSD: gem.c,v 1.56 2007/04/12 06:14:40 dyoung Exp $ */
/*
*
@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: gem.c,v 1.55 2007/04/12 05:56:01 dyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: gem.c,v 1.56 2007/04/12 06:14:40 dyoung Exp $");
#include "opt_inet.h"
#include "bpfilter.h"
@ -1473,6 +1473,7 @@ gem_rint(sc)
rxstat = GEM_DMA_READ(sc, sc->sc_rxdescs[i].gd_flags);
if (rxstat & GEM_RD_OWN) {
GEM_CDRXSYNC(sc, i, BUS_DMASYNC_PREREAD);
/*
* We have processed all of the receive buffers.
*/

View File

@ -1,4 +1,4 @@
/* $NetBSD: gemreg.h,v 1.9 2006/11/24 13:01:07 martin Exp $ */
/* $NetBSD: gemreg.h,v 1.10 2007/04/12 06:14:47 dyoung Exp $ */
/*
*
@ -583,8 +583,8 @@
* GEM descriptor table structures.
*/
struct gem_desc {
uint64_t gd_flags;
uint64_t gd_addr;
volatile uint64_t gd_flags;
volatile uint64_t gd_addr;
};
/* Transmit flags */