From 8766dee5da4701cfc708b07f12a8e29bee83ecd2 Mon Sep 17 00:00:00 2001 From: kettenis Date: Tue, 6 Oct 2015 15:21:16 +0000 Subject: [PATCH] Make sure that tx_buffer->next_eop is properly set before we bump the number of available descriptors, such that the interrupt handler doesn't attempt to complete partially initialized descriptors. Seems to fix the watchdog timeouts reported by various people. Tested by Mattieu Baptiste and Gregor Best. ok mikeb@ --- sys/dev/pci/if_em.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/sys/dev/pci/if_em.c b/sys/dev/pci/if_em.c index 94d906b6572..9b860d5a72f 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.306 2015/09/30 11:25:08 kettenis Exp $ */ +/* $OpenBSD: if_em.c,v 1.307 2015/10/06 15:21:16 kettenis Exp $ */ /* $FreeBSD: if_em.c,v 1.46 2004/09/29 18:28:28 mlaier Exp $ */ #include @@ -1210,12 +1210,6 @@ em_encap(struct em_softc *sc, struct mbuf *m_head) } } - 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); - #if NVLAN > 0 /* Find out if we are in VLAN mode */ if (m_head->m_flags & M_VLANTAG) { @@ -1249,6 +1243,14 @@ 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 @@ -2378,6 +2380,8 @@ 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; @@ -2403,6 +2407,8 @@ em_txeof(struct em_softc *sc) if (sc->num_tx_desc_avail == sc->num_tx_desc) return; + membar_consumer(); + first = sc->next_tx_to_clean; tx_desc = &sc->tx_desc_base[first]; tx_buffer = &sc->tx_buffer_area[first]; -- 2.20.1