summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorchuck <chuck@cvs.openbsd.org>1996-07-11 22:47:08 +0000
committerchuck <chuck@cvs.openbsd.org>1996-07-11 22:47:08 +0000
commit8200370c0985d52f41b8d12b436b648e128e2823 (patch)
tree58bc864c9da5256dd375c09c36e327e7caf46ab6 /sys
parentb4802fd04a95be8a637b50af9c19b65dd1e7e65f (diff)
fix:
- en_mfix shouldn't touch M_EXT mbufs. change to avoid this [at the expense of allocating a new cluster mbuf to copy to]. XXX: en_mfix is getting called more often than I hoped it would (seems to happen when TCP retransmits... we get all sorts of odd sized, odd lengthed data mbufs, yuck). i may revise the xmit DMA code to use non-word sized dma.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/ic/midway.c82
-rw-r--r--sys/dev/ic/midwayvar.h3
2 files changed, 63 insertions, 22 deletions
diff --git a/sys/dev/ic/midway.c b/sys/dev/ic/midway.c
index e50d73d48d1..3443c60de4c 100644
--- a/sys/dev/ic/midway.c
+++ b/sys/dev/ic/midway.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: midway.c,v 1.9 1996/07/11 00:17:10 chuck Exp $ */
-/* (sync'd to midway.c 1.58) */
+/* $OpenBSD: midway.c,v 1.10 1996/07/11 22:47:04 chuck Exp $ */
+/* (sync'd to midway.c 1.59) */
/*
*
@@ -340,7 +340,7 @@ STATIC void en_init __P((struct en_softc *));
STATIC int en_ioctl __P((struct ifnet *, EN_IOCTL_CMDT, caddr_t));
STATIC int en_k2sz __P((int));
STATIC void en_loadvc __P((struct en_softc *, int));
-STATIC void en_mfix __P((struct en_softc *, struct mbuf *));
+STATIC int en_mfix __P((struct en_softc *, struct mbuf **, struct mbuf *));
STATIC struct mbuf *en_mget __P((struct en_softc *, u_int, u_int *));
STATIC int en_rxctl __P((struct en_softc *, struct atm_pseudoioctl *, int));
STATIC void en_txdma __P((struct en_softc *, int));
@@ -663,7 +663,7 @@ done_probe:
sc->vtrash = sc->otrash = sc->mfix = sc->txmbovr = sc->dmaovr = 0;
sc->txoutspace = sc->txdtqout = sc->launch = sc->lheader = sc->ltail = 0;
sc->hwpull = sc->swadd = sc->rxqnotus = sc->rxqus = sc->rxoutboth = 0;
- sc->rxdrqout = sc->ttrash = sc->rxmbufout = 0;
+ sc->rxdrqout = sc->ttrash = sc->rxmbufout = sc->mfixfail = 0;
#endif
sc->need_drqs = sc->need_dtqs = 0;
@@ -1274,9 +1274,9 @@ struct ifnet *ifp;
{
struct en_softc *sc = (struct en_softc *) ifp->if_softc;
struct ifqueue *ifq = &ifp->if_snd; /* if INPUT QUEUE */
- struct mbuf *m, *lastm;
+ struct mbuf *m, *lastm, *prev;
struct atm_pseudohdr *ap, *new_ap;
- int txchan, c, mlen, got, need, toadd, cellcnt;
+ int txchan, c, mlen, got, need, toadd, cellcnt, first;
u_int32_t atm_vpi, atm_vci, atm_flags, *dat, aal;
u_int8_t *cp;
@@ -1304,16 +1304,29 @@ struct ifnet *ifp;
lastm = m;
mlen = 0;
+ prev = NULL;
while (1) {
if ( (mtod(lastm, u_int) % sizeof(u_int32_t)) != 0 ||
- ((lastm->m_len % sizeof(u_int32_t)) != 0 && lastm->m_next))
- en_mfix(sc, lastm);
+ ((lastm->m_len % sizeof(u_int32_t)) != 0 && lastm->m_next)) {
+ first = (lastm == m);
+ if (en_mfix(sc, &lastm, prev) == 0) { /* failed? */
+ m_freem(m);
+ m = NULL;
+ break;
+ }
+ if (first)
+ m = lastm; /* update */
+ }
mlen += lastm->m_len;
if (lastm->m_next == NULL)
break;
+ prev = lastm;
lastm = lastm->m_next;
}
+ if (m == NULL) /* happens only if mfix fails */
+ continue;
+
ap = mtod(m, struct atm_pseudohdr *);
atm_vpi = ATM_PH_VPI(ap);
@@ -1447,33 +1460,61 @@ struct ifnet *ifp;
* en_mfix: fix a stupid mbuf
*/
-STATIC void en_mfix(sc, m)
+STATIC int en_mfix(sc, mm, prev)
struct en_softc *sc;
-struct mbuf *m;
+struct mbuf **mm, *prev;
{
- u_char *d = mtod(m, u_char *), *cp;
- int off = ((u_int) d) % sizeof(u_int32_t);
+ struct mbuf *m, *new;
+ u_char *d, *cp;
+ int off;
struct mbuf *nxt;
+ m = *mm;
+
EN_COUNT(sc->mfix); /* count # of calls */
#ifdef EN_DEBUG
printf("%s: mfix mbuf m_data=0x%x, m_len=%d\n", sc->sc_dev.dv_xname,
m->m_data, m->m_len);
#endif
+ d = mtod(m, u_char *);
+ off = ((u_int) d) % sizeof(u_int32_t);
+
if (off) {
- bcopy(d, d - off, m->m_len); /* ALIGN! (with costly data copy...) */
- d -= off;
- m->m_data = (caddr_t)d;
+ if ((m->m_flags & M_EXT) == 0) {
+ bcopy(d, d - off, m->m_len); /* ALIGN! (with costly data copy...) */
+ d -= off;
+ m->m_data = (caddr_t)d;
+ } else {
+ /* can't write to an M_EXT mbuf since it may be shared */
+ MGET(new, M_DONTWAIT, MT_DATA);
+ if (!new) {
+ EN_COUNT(sc->mfixfail);
+ return(0);
+ }
+ MCLGET(new, M_DONTWAIT);
+ if ((new->m_flags & M_EXT) == 0) {
+ m_free(new);
+ EN_COUNT(sc->mfixfail);
+ return(0);
+ }
+ bcopy(d, new->m_data, m->m_len); /* ALIGN! (with costly data copy...) */
+ new->m_len = m->m_len;
+ new->m_next = m->m_next;
+ if (prev)
+ prev->m_next = new;
+ m_free(m);
+ *mm = m = new; /* note: 'd' now invalid */
+ }
}
off = m->m_len % sizeof(u_int32_t);
if (off == 0)
- return;
+ return(1);
- d = d + m->m_len;
+ d = mtod(m, u_char *) + m->m_len;
off = sizeof(u_int32_t) - off;
nxt = m->m_next;
@@ -1490,12 +1531,10 @@ struct mbuf *m;
nxt->m_len--;
nxt->m_data = (caddr_t)cp;
}
- return;
+ return(1);
}
-
-
/*
* en_txdma: start trasmit DMA, if possible
*/
@@ -2590,7 +2629,8 @@ int unit, level;
if (level & END_STATS) {
printf(" en_stats:\n");
- printf(" %d mbufs fixed by mfix (should be zero)\n", sc->mfix);
+ printf(" %d mbufs fixed by mfix (%d failures)\n",
+ sc->mfix, sc->mfixfail);
printf(" %d rx dma overflow interrupts\n", sc->dmaovr);
printf(" %d times we ran out of TX space and stalled\n",
sc->txoutspace);
diff --git a/sys/dev/ic/midwayvar.h b/sys/dev/ic/midwayvar.h
index 86b07f41548..c44f34eb836 100644
--- a/sys/dev/ic/midwayvar.h
+++ b/sys/dev/ic/midwayvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: midwayvar.h,v 1.6 1996/07/03 17:21:18 chuck Exp $ */
+/* $OpenBSD: midwayvar.h,v 1.7 1996/07/11 22:47:07 chuck Exp $ */
/*
*
@@ -163,6 +163,7 @@ struct en_softc {
u_int32_t otrash; /* sw copy of counter */
u_int32_t ttrash; /* # of RBD's with T bit set */
u_int32_t mfix; /* # of times we had to call mfix */
+ u_int32_t mfixfail; /* # of times mfix failed */
u_int32_t txmbovr; /* # of times we dropped due to mbsize */
u_int32_t dmaovr; /* tx dma overflow count */
u_int32_t txoutspace; /* out of space in xmit buffer */