From e60a42f980067db5924e28c8a23a41768b12cdfe Mon Sep 17 00:00:00 2001 From: silby Date: Sat, 29 Mar 2003 17:50:37 +0000 Subject: Have sis_encap use m_defrag if: 1. The chain passed in is > 31 fragments long or 2. The chain will not fit in the remaining descriptors without defragmentation. This is slightly less clear than other network drivers because the sis chips share one descriptor list for all packets, it seems. Before this change, a > 127 fragment chain would get stuck in the IFQUEUE permanently, bringing all network traffic to a halt. MFC after: 2 weeks --- sys/pci/if_sis.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'sys/pci/if_sis.c') diff --git a/sys/pci/if_sis.c b/sys/pci/if_sis.c index 7f72c39..fa4006e 100644 --- a/sys/pci/if_sis.c +++ b/sys/pci/if_sis.c @@ -1878,9 +1878,33 @@ sis_encap(sc, m_head, txidx) { struct sis_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 (SIS_TX_LIST_CNT - sc->sis_cdata.sis_tx_cnt < 2) + 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 > SIS_TX_LIST_CNT / 4) || + ((SIS_TX_LIST_CNT - (chainlen + sc->sis_cdata.sis_tx_cnt)) < 2)) { + 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. -- cgit v1.1