summaryrefslogtreecommitdiff
path: root/sys/dev/ic
diff options
context:
space:
mode:
authorBrad Smith <brad@cvs.openbsd.org>2006-01-11 03:57:51 +0000
committerBrad Smith <brad@cvs.openbsd.org>2006-01-11 03:57:51 +0000
commitca9c168942be880e28f6313d18dd0b7357942776 (patch)
tree81161fa4fc250a4aff2309f74d47fc38167960be /sys/dev/ic
parentaf73359bcb355eda5b4a638e94ce09717d1be680 (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')
-rw-r--r--sys/dev/ic/xl.c37
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);