summaryrefslogtreecommitdiffstats
path: root/sys/pci
diff options
context:
space:
mode:
authorsilby <silby@FreeBSD.org>2003-03-29 21:27:07 +0000
committersilby <silby@FreeBSD.org>2003-03-29 21:27:07 +0000
commit643eecc671ff85c53661f48339faa36468a3ad12 (patch)
treeab86e9430834f256ef14d34745df1137a95a4b01 /sys/pci
parent38b7c6755f4adcd65c6f27259b00722b44c08b06 (diff)
downloadFreeBSD-src-643eecc671ff85c53661f48339faa36468a3ad12.zip
FreeBSD-src-643eecc671ff85c53661f48339faa36468a3ad12.tar.gz
Update if_dc to use m_defrag, removing the semi-duplicate dc_coal
function. Also, use m_defrag where appropriate to defrag long mbuf chains in the same fashion as was done in if_sis.c. Before this change, if_dc would blow up and take down the interface if fed a really long mbuf chain. MFC after: 2 weeks
Diffstat (limited to 'sys/pci')
-rw-r--r--sys/pci/if_dc.c65
1 files changed, 30 insertions, 35 deletions
diff --git a/sys/pci/if_dc.c b/sys/pci/if_dc.c
index 1a73dc9..ca72682 100644
--- a/sys/pci/if_dc.c
+++ b/sys/pci/if_dc.c
@@ -208,7 +208,6 @@ static void dc_acpi (device_t);
static struct dc_type *dc_devtype (device_t);
static int dc_newbuf (struct dc_softc *, int, struct mbuf *);
static int dc_encap (struct dc_softc *, struct mbuf *, u_int32_t *);
-static int dc_coal (struct dc_softc *, struct mbuf **);
static void dc_pnic_rx_bug_war (struct dc_softc *, int);
static int dc_rx_resync (struct dc_softc *);
static void dc_rxeof (struct dc_softc *);
@@ -3126,9 +3125,33 @@ dc_encap(sc, m_head, txidx)
{
struct dc_desc *f = NULL;
struct mbuf *m;
- int frag, cur, cnt = 0;
+ int frag, cur, cnt = 0, chainlen = 0;
/*
+ * If there's no way we can send any packets, return now.
+ */
+ if (DC_TX_LIST_CNT - sc->dc_cdata.dc_tx_cnt < 6)
+ return (ENOBUFS);
+
+ /*
+ * Count the number of frags in this chain to see if
+ * we need to m_defrag. Since the descriptor list is shared
+ * by all packets, we'll m_defrag long chains so that they
+ * do not use up the entire list, even if they would fit.
+ */
+
+ for (m = m_head; m != NULL; m = m->m_next)
+ chainlen++;
+
+ if ((chainlen > DC_TX_LIST_CNT / 4) ||
+ ((DC_TX_LIST_CNT - (chainlen + sc->dc_cdata.dc_tx_cnt)) < 6)) {
+ m = m_defrag(m_head, M_DONTWAIT);
+ if (m == NULL)
+ return (ENOBUFS);
+ m_head = m;
+ }
+
+ /*
* Start packing the mbufs in this chain into
* the fragment pointers. Stop when we run out
* of fragments or hit the end of the mbuf chain.
@@ -3180,37 +3203,6 @@ dc_encap(sc, m_head, txidx)
}
/*
- * Coalesce an mbuf chain into a single mbuf cluster buffer.
- * Needed for some really badly behaved chips that just can't
- * do scatter/gather correctly.
- */
-static int
-dc_coal(sc, m_head)
- struct dc_softc *sc;
- struct mbuf **m_head;
-{
- struct mbuf *m_new, *m;
-
- m = *m_head;
- MGETHDR(m_new, M_DONTWAIT, MT_DATA);
- if (m_new == NULL)
- return(ENOBUFS);
- if (m->m_pkthdr.len > MHLEN) {
- MCLGET(m_new, M_DONTWAIT);
- if (!(m_new->m_flags & M_EXT)) {
- m_freem(m_new);
- return(ENOBUFS);
- }
- }
- m_copydata(m, 0, m->m_pkthdr.len, mtod(m_new, caddr_t));
- m_new->m_pkthdr.len = m_new->m_len = m->m_pkthdr.len;
- m_freem(m);
- *m_head = m_new;
-
- return(0);
-}
-
-/*
* Main transmit routine. To avoid having to do mbuf copies, we put pointers
* to the mbuf data regions directly in the transmit lists. We also save a
* copy of the pointers since the transmit list fragment pointers are
@@ -3222,7 +3214,7 @@ dc_start(ifp)
struct ifnet *ifp;
{
struct dc_softc *sc;
- struct mbuf *m_head = NULL;
+ struct mbuf *m_head = NULL, *m;
int idx;
sc = ifp->if_softc;
@@ -3249,10 +3241,13 @@ dc_start(ifp)
if (sc->dc_flags & DC_TX_COALESCE &&
(m_head->m_next != NULL ||
sc->dc_flags & DC_TX_ALIGN)) {
- if (dc_coal(sc, &m_head)) {
+ m = m_defrag(m_head, M_DONTWAIT);
+ if (m == NULL) {
IF_PREPEND(&ifp->if_snd, m_head);
ifp->if_flags |= IFF_OACTIVE;
break;
+ } else {
+ m_head = m;
}
}
OpenPOWER on IntegriCloud