summaryrefslogtreecommitdiff
path: root/sys/dev/ic
diff options
context:
space:
mode:
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);