summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/if_em.c79
1 files changed, 44 insertions, 35 deletions
diff --git a/sys/dev/pci/if_em.c b/sys/dev/pci/if_em.c
index 31d7d2336d4..3739ad6b41c 100644
--- a/sys/dev/pci/if_em.c
+++ b/sys/dev/pci/if_em.c
@@ -31,7 +31,7 @@ POSSIBILITY OF SUCH DAMAGE.
***************************************************************************/
-/* $OpenBSD: if_em.c,v 1.311 2015/11/20 03:35:23 dlg Exp $ */
+/* $OpenBSD: if_em.c,v 1.312 2015/11/20 13:11:16 mpi Exp $ */
/* $FreeBSD: if_em.c,v 1.46 2004/09/29 18:28:28 mlaier Exp $ */
#include <dev/pci/if_em.h>
@@ -918,17 +918,20 @@ em_intr(void *arg)
if (reg_icr & E1000_ICR_RXO)
sc->rx_overruns++;
+ KERNEL_LOCK();
+
/* Link status change */
if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
- KERNEL_LOCK();
sc->hw.get_link_status = 1;
em_check_for_link(&sc->hw);
em_update_link_status(sc);
- if (!IFQ_IS_EMPTY(&ifp->if_snd))
- em_start(ifp);
- KERNEL_UNLOCK();
}
+ if (ifp->if_flags & IFF_RUNNING && !IFQ_IS_EMPTY(&ifp->if_snd))
+ em_start(ifp);
+
+ KERNEL_UNLOCK();
+
if (refill && em_rxfill(sc)) {
/* Advance the Rx Queue #0 "Tail Pointer". */
E1000_WRITE_REG(&sc->hw, RDT, sc->last_rx_desc_filled);
@@ -1105,10 +1108,17 @@ em_encap(struct em_softc *sc, struct mbuf *m_head)
struct em_buffer *tx_buffer, *tx_buffer_mapped;
struct em_tx_desc *current_tx_desc = NULL;
- /* Check that we have least the minimal number of TX descriptors. */
- if (sc->num_tx_desc_avail <= EM_TX_OP_THRESHOLD) {
- sc->no_tx_desc_avail1++;
- return (ENOBUFS);
+ /*
+ * Force a cleanup if number of TX descriptors
+ * available hits the threshold
+ */
+ if (sc->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) {
+ em_txeof(sc);
+ /* Now do we at least have a minimal? */
+ if (sc->num_tx_desc_avail <= EM_TX_OP_THRESHOLD) {
+ sc->no_tx_desc_avail1++;
+ return (ENOBUFS);
+ }
}
if (sc->hw.mac_type == em_82547) {
@@ -1210,6 +1220,12 @@ em_encap(struct em_softc *sc, struct mbuf *m_head)
}
}
+ sc->next_avail_tx_desc = i;
+ if (sc->pcix_82544)
+ sc->num_tx_desc_avail -= txd_used;
+ else
+ sc->num_tx_desc_avail -= map->dm_nsegs;
+
#if NVLAN > 0
/* Find out if we are in VLAN mode */
if (m_head->m_flags & M_VLANTAG) {
@@ -1243,14 +1259,6 @@ em_encap(struct em_softc *sc, struct mbuf *m_head)
tx_buffer = &sc->tx_buffer_area[first];
tx_buffer->next_eop = last;
- membar_producer();
-
- sc->next_avail_tx_desc = i;
- if (sc->pcix_82544)
- atomic_sub_int(&sc->num_tx_desc_avail, txd_used);
- else
- atomic_sub_int(&sc->num_tx_desc_avail, map->dm_nsegs);
-
/*
* Advance the Transmit Descriptor Tail (Tdt),
* this tells the E1000 that this frame is
@@ -2380,12 +2388,10 @@ em_transmit_checksum_setup(struct em_softc *sc, struct mbuf *mp,
tx_buffer->m_head = NULL;
tx_buffer->next_eop = -1;
- membar_producer();
-
if (++curr_txd == sc->num_tx_desc)
curr_txd = 0;
- atomic_dec_int(&sc->num_tx_desc_avail);
+ sc->num_tx_desc_avail--;
sc->next_avail_tx_desc = curr_txd;
}
@@ -2399,7 +2405,7 @@ em_transmit_checksum_setup(struct em_softc *sc, struct mbuf *mp,
void
em_txeof(struct em_softc *sc)
{
- int first, last, done, num_avail, free = 0;
+ int first, last, done, num_avail;
struct em_buffer *tx_buffer;
struct em_tx_desc *tx_desc, *eop_desc;
struct ifnet *ifp = &sc->interface_data.ac_if;
@@ -2407,8 +2413,9 @@ em_txeof(struct em_softc *sc)
if (sc->num_tx_desc_avail == sc->num_tx_desc)
return;
- membar_consumer();
+ KERNEL_LOCK();
+ num_avail = sc->num_tx_desc_avail;
first = sc->next_tx_to_clean;
tx_desc = &sc->tx_desc_base[first];
tx_buffer = &sc->tx_buffer_area[first];
@@ -2432,7 +2439,7 @@ em_txeof(struct em_softc *sc)
while (first != done) {
tx_desc->upper.data = 0;
tx_desc->lower.data = 0;
- free++;
+ num_avail++;
if (tx_buffer->m_head != NULL) {
ifp->if_opackets++;
@@ -2472,23 +2479,25 @@ em_txeof(struct em_softc *sc)
sc->next_tx_to_clean = first;
- num_avail = atomic_add_int_nv(&sc->num_tx_desc_avail, free);
+ /*
+ * If we have enough room, clear IFF_OACTIVE to tell the stack
+ * that it is OK to send packets.
+ * If there are no pending descriptors, clear the timeout. Otherwise,
+ * if some descriptors have been freed, restart the timeout.
+ */
+ if (num_avail > EM_TX_CLEANUP_THRESHOLD)
+ ifp->if_flags &= ~IFF_OACTIVE;
/* All clean, turn off the timer */
if (num_avail == sc->num_tx_desc)
ifp->if_timer = 0;
+ /* Some cleaned, reset the timer */
+ else if (num_avail != sc->num_tx_desc_avail)
+ ifp->if_timer = EM_TX_TIMEOUT;
- /*
- * If we have enough room, clear IFF_OACTIVE to tell the stack
- * that it is OK to send packets.
- */
- if (ISSET(ifp->if_flags, IFF_OACTIVE) &&
- num_avail > EM_TX_OP_THRESHOLD) {
- KERNEL_LOCK();
- CLR(ifp->if_flags, IFF_OACTIVE);
- em_start(ifp);
- KERNEL_UNLOCK();
- }
+ sc->num_tx_desc_avail = num_avail;
+
+ KERNEL_UNLOCK();
}
/*********************************************************************