mirror of
https://github.com/freebsd/freebsd-src
synced 2024-09-30 21:54:50 +00:00
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
This commit is contained in:
parent
2af5e4d96f
commit
cda97c506e
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=112819
|
@ -208,7 +208,6 @@ static void dc_acpi (device_t);
|
||||||
static struct dc_type *dc_devtype (device_t);
|
static struct dc_type *dc_devtype (device_t);
|
||||||
static int dc_newbuf (struct dc_softc *, int, struct mbuf *);
|
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_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 void dc_pnic_rx_bug_war (struct dc_softc *, int);
|
||||||
static int dc_rx_resync (struct dc_softc *);
|
static int dc_rx_resync (struct dc_softc *);
|
||||||
static void dc_rxeof (struct dc_softc *);
|
static void dc_rxeof (struct dc_softc *);
|
||||||
|
@ -3126,8 +3125,32 @@ dc_encap(sc, m_head, txidx)
|
||||||
{
|
{
|
||||||
struct dc_desc *f = NULL;
|
struct dc_desc *f = NULL;
|
||||||
struct mbuf *m;
|
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
|
* Start packing the mbufs in this chain into
|
||||||
* the fragment pointers. Stop when we run out
|
* the fragment pointers. Stop when we run out
|
||||||
|
@ -3179,37 +3202,6 @@ dc_encap(sc, m_head, txidx)
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* 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
|
* 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
|
* to the mbuf data regions directly in the transmit lists. We also save a
|
||||||
|
@ -3222,7 +3214,7 @@ dc_start(ifp)
|
||||||
struct ifnet *ifp;
|
struct ifnet *ifp;
|
||||||
{
|
{
|
||||||
struct dc_softc *sc;
|
struct dc_softc *sc;
|
||||||
struct mbuf *m_head = NULL;
|
struct mbuf *m_head = NULL, *m;
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
sc = ifp->if_softc;
|
sc = ifp->if_softc;
|
||||||
|
@ -3249,10 +3241,13 @@ dc_start(ifp)
|
||||||
if (sc->dc_flags & DC_TX_COALESCE &&
|
if (sc->dc_flags & DC_TX_COALESCE &&
|
||||||
(m_head->m_next != NULL ||
|
(m_head->m_next != NULL ||
|
||||||
sc->dc_flags & DC_TX_ALIGN)) {
|
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);
|
IF_PREPEND(&ifp->if_snd, m_head);
|
||||||
ifp->if_flags |= IFF_OACTIVE;
|
ifp->if_flags |= IFF_OACTIVE;
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
m_head = m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -208,7 +208,6 @@ static void dc_acpi (device_t);
|
||||||
static struct dc_type *dc_devtype (device_t);
|
static struct dc_type *dc_devtype (device_t);
|
||||||
static int dc_newbuf (struct dc_softc *, int, struct mbuf *);
|
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_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 void dc_pnic_rx_bug_war (struct dc_softc *, int);
|
||||||
static int dc_rx_resync (struct dc_softc *);
|
static int dc_rx_resync (struct dc_softc *);
|
||||||
static void dc_rxeof (struct dc_softc *);
|
static void dc_rxeof (struct dc_softc *);
|
||||||
|
@ -3126,8 +3125,32 @@ dc_encap(sc, m_head, txidx)
|
||||||
{
|
{
|
||||||
struct dc_desc *f = NULL;
|
struct dc_desc *f = NULL;
|
||||||
struct mbuf *m;
|
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
|
* Start packing the mbufs in this chain into
|
||||||
* the fragment pointers. Stop when we run out
|
* the fragment pointers. Stop when we run out
|
||||||
|
@ -3179,37 +3202,6 @@ dc_encap(sc, m_head, txidx)
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* 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
|
* 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
|
* to the mbuf data regions directly in the transmit lists. We also save a
|
||||||
|
@ -3222,7 +3214,7 @@ dc_start(ifp)
|
||||||
struct ifnet *ifp;
|
struct ifnet *ifp;
|
||||||
{
|
{
|
||||||
struct dc_softc *sc;
|
struct dc_softc *sc;
|
||||||
struct mbuf *m_head = NULL;
|
struct mbuf *m_head = NULL, *m;
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
sc = ifp->if_softc;
|
sc = ifp->if_softc;
|
||||||
|
@ -3249,10 +3241,13 @@ dc_start(ifp)
|
||||||
if (sc->dc_flags & DC_TX_COALESCE &&
|
if (sc->dc_flags & DC_TX_COALESCE &&
|
||||||
(m_head->m_next != NULL ||
|
(m_head->m_next != NULL ||
|
||||||
sc->dc_flags & DC_TX_ALIGN)) {
|
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);
|
IF_PREPEND(&ifp->if_snd, m_head);
|
||||||
ifp->if_flags |= IFF_OACTIVE;
|
ifp->if_flags |= IFF_OACTIVE;
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
m_head = m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue