summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkettenis <kettenis@openbsd.org>2016-05-04 18:38:57 +0000
committerkettenis <kettenis@openbsd.org>2016-05-04 18:38:57 +0000
commit29e604b79983cfdb4ae6f7b64f3efd9a17b62317 (patch)
treeab16486d49a2626742ddccfa37217a2f64f783ce
parentSome hardware (such as the onboard dc(4) of the Netra X1) has a broken DMA (diff)
downloadwireguard-openbsd-29e604b79983cfdb4ae6f7b64f3efd9a17b62317.tar.xz
wireguard-openbsd-29e604b79983cfdb4ae6f7b64f3efd9a17b62317.zip
Use BUS_DMA_OVERRUN to cope with the broken DMA engine of the Davicom DM9102
found on some Sun sparc64 machines. This fixes the unrecoverable DMA errors people have been seeing ever since dlg@ made changes to the pool code that changes the memory layout.
-rw-r--r--sys/dev/ic/dc.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/sys/dev/ic/dc.c b/sys/dev/ic/dc.c
index d68af6ace33..714b3a51473 100644
--- a/sys/dev/ic/dc.c
+++ b/sys/dev/ic/dc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dc.c,v 1.150 2016/04/13 10:49:26 mpi Exp $ */
+/* $OpenBSD: dc.c,v 1.151 2016/05/04 18:38:57 kettenis Exp $ */
/*
* Copyright (c) 1997, 1998, 1999
@@ -122,6 +122,18 @@
#include <dev/ic/dcreg.h>
+/*
+ * The Davicom DM9102 has a broken DMA engine that reads beyond the
+ * end of the programmed transfer. Architectures with a proper IOMMU
+ * (such as sparc64) will trap on this access. To avoid having to
+ * copy each transmitted mbuf to guarantee enough trailing space,
+ * those architectures should implement BUS_DMA_OVERRUN that takes
+ * appropriate action to tolerate this behaviour.
+ */
+#ifndef BUS_DMA_OVERRUN
+#define BUS_DMA_OVERRUN 0
+#endif
+
int dc_intr(void *);
struct dc_type *dc_devtype(void *);
int dc_newbuf(struct dc_softc *, int, struct mbuf *);
@@ -2583,13 +2595,13 @@ dc_start(struct ifnet *ifp)
map = sc->sc_tx_sparemap;
switch (bus_dmamap_load_mbuf(sc->sc_dmat, map, m,
- BUS_DMA_NOWAIT)) {
+ BUS_DMA_NOWAIT | BUS_DMA_OVERRUN)) {
case 0:
break;
case EFBIG:
if (m_defrag(m, M_DONTWAIT) == 0 &&
bus_dmamap_load_mbuf(sc->sc_dmat, map, m,
- BUS_DMA_NOWAIT) == 0)
+ BUS_DMA_NOWAIT | BUS_DMA_OVERRUN) == 0)
break;
/* FALLTHROUGH */