diff options
author | Brad Smith <brad@cvs.openbsd.org> | 2006-01-11 03:57:51 +0000 |
---|---|---|
committer | Brad Smith <brad@cvs.openbsd.org> | 2006-01-11 03:57:51 +0000 |
commit | ca9c168942be880e28f6313d18dd0b7357942776 (patch) | |
tree | 81161fa4fc250a4aff2309f74d47fc38167960be /sys/dev/ic/xl.c | |
parent | af73359bcb355eda5b4a638e94ce09717d1be680 (diff) |
In the case that we've used up all 63 fragments then try to allocate an mbuf
cluster and copy the mbuf chain. The codepath for older xl's already dealt
with this condition.
Diffstat (limited to 'sys/dev/ic/xl.c')
-rw-r--r-- | sys/dev/ic/xl.c | 37 |
1 files changed, 36 insertions, 1 deletions
diff --git a/sys/dev/ic/xl.c b/sys/dev/ic/xl.c index d048e64d971..3ba6299768c 100644 --- a/sys/dev/ic/xl.c +++ b/sys/dev/ic/xl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: xl.c,v 1.66 2005/11/07 03:20:00 brad Exp $ */ +/* $OpenBSD: xl.c,v 1.67 2006/01/11 03:57:50 brad Exp $ */ /* * Copyright (c) 1997, 1998, 1999 @@ -1914,6 +1914,7 @@ xl_encap_90xB(sc, c, m_head) d->xl_status = htole32(0); d->xl_next = 0; +reload: if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m_head, BUS_DMA_NOWAIT) != 0) return (ENOBUFS); @@ -1926,6 +1927,40 @@ xl_encap_90xB(sc, c, m_head) f->xl_len = htole32(map->dm_segs[frag].ds_len); } + /* + * Handle special case: we used up all 63 fragments, + * but we have more mbufs left in the chain. Copy the + * data into an mbuf cluster. Note that we don't + * bother clearing the values in the other fragment + * pointers/counters; it wouldn't gain us anything, + * and would waste cycles. + */ + if (frag != map->dm_nsegs) { + struct mbuf *m_new = NULL; + + printf("%s: allocating a cluster\n", sc->sc_dev.dv_xname); + + MGETHDR(m_new, M_DONTWAIT, MT_DATA); + if (m_new == NULL) { + m_freem(m_head); + return (1); + } + if (m_head->m_pkthdr.len > MHLEN) { + MCLGET(m_new, M_DONTWAIT); + if (!(m_new->m_flags & M_EXT)) { + m_freem(m_new); + m_freem(m_head); + return (1); + } + } + m_copydata(m_head, 0, m_head->m_pkthdr.len, + mtod(m_new, caddr_t)); + m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; + m_freem(m_head); + m_head = m_new; + goto reload; + } + bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, BUS_DMASYNC_PREWRITE); |