diff options
author | chuck <chuck@cvs.openbsd.org> | 1996-07-11 22:47:08 +0000 |
---|---|---|
committer | chuck <chuck@cvs.openbsd.org> | 1996-07-11 22:47:08 +0000 |
commit | 8200370c0985d52f41b8d12b436b648e128e2823 (patch) | |
tree | 58bc864c9da5256dd375c09c36e327e7caf46ab6 /sys | |
parent | b4802fd04a95be8a637b50af9c19b65dd1e7e65f (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.c | 82 | ||||
-rw-r--r-- | sys/dev/ic/midwayvar.h | 3 |
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 */ |