Module Name: src Committed By: msaitoh Date: Fri May 18 10:09:02 UTC 2018
Modified Files: src/sys/dev/pci/ixgbe: ix_txrx.c ixgbe.c ixgbe.h ixv.c Log Message: Revert new watchdog timer commits. The new watchdog timer made stability worse than before. It seems unknown problems exists. http://mail-index.netbsd.org/source-changes/2018/05/08/msg095020.html http://mail-index.netbsd.org/source-changes/2018/05/16/msg095240.html To generate a diff of this commit: cvs rdiff -u -r1.44 -r1.45 src/sys/dev/pci/ixgbe/ix_txrx.c cvs rdiff -u -r1.152 -r1.153 src/sys/dev/pci/ixgbe/ixgbe.c cvs rdiff -u -r1.47 -r1.48 src/sys/dev/pci/ixgbe/ixgbe.h cvs rdiff -u -r1.97 -r1.98 src/sys/dev/pci/ixgbe/ixv.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/pci/ixgbe/ix_txrx.c diff -u src/sys/dev/pci/ixgbe/ix_txrx.c:1.44 src/sys/dev/pci/ixgbe/ix_txrx.c:1.45 --- src/sys/dev/pci/ixgbe/ix_txrx.c:1.44 Wed May 16 08:08:24 2018 +++ src/sys/dev/pci/ixgbe/ix_txrx.c Fri May 18 10:09:02 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: ix_txrx.c,v 1.44 2018/05/16 08:08:24 msaitoh Exp $ */ +/* $NetBSD: ix_txrx.c,v 1.45 2018/05/18 10:09:02 msaitoh Exp $ */ /****************************************************************************** @@ -130,10 +130,9 @@ static void ixgbe_setup_hw_rsc(struct rx int ixgbe_legacy_start_locked(struct ifnet *ifp, struct tx_ring *txr) { + int rc; struct mbuf *m_head; struct adapter *adapter = txr->adapter; - int enqueued = 0; - int rc; IXGBE_TX_LOCK_ASSERT(txr); @@ -159,7 +158,6 @@ ixgbe_legacy_start_locked(struct ifnet * if ((rc = ixgbe_xmit(txr, m_head)) == EAGAIN) { break; } - enqueued++; IFQ_DEQUEUE(&ifp->if_snd, m_head); if (rc != 0) { m_freem(m_head); @@ -170,11 +168,6 @@ ixgbe_legacy_start_locked(struct ifnet * bpf_mtap(ifp, m_head); } - if (enqueued) { - txr->lastsent = time_uptime; - txr->sending = true; - } - return IXGBE_SUCCESS; } /* ixgbe_legacy_start_locked */ @@ -323,11 +316,6 @@ ixgbe_mq_start_locked(struct ifnet *ifp, break; } - if (enqueued) { - txr->lastsent = time_uptime; - txr->sending = true; - } - if (txr->tx_avail < IXGBE_TX_CLEANUP_THRESHOLD(txr->adapter)) ixgbe_txeof(txr); @@ -552,6 +540,10 @@ retry: if (m_head->m_flags & M_MCAST) ifp->if_omcasts++; + /* Mark queue as having work */ + if (txr->busy == 0) + txr->busy = 1; + return (0); } /* ixgbe_xmit */ @@ -677,7 +669,6 @@ ixgbe_setup_transmit_ring(struct tx_ring /* Free any existing tx buffers. */ txbuf = txr->tx_buffers; for (int i = 0; i < txr->num_desc; i++, txbuf++) { - txr->sending = false; if (txbuf->m_head != NULL) { bus_dmamap_sync(txr->txtag->dt_dmat, txbuf->map, 0, txbuf->m_head->m_pkthdr.len, @@ -1138,7 +1129,7 @@ ixgbe_txeof(struct tx_ring *txr) #endif /* DEV_NETMAP */ if (txr->tx_avail == txr->num_desc) { - txr->sending = false; + txr->busy = 0; return false; } @@ -1220,8 +1211,25 @@ ixgbe_txeof(struct tx_ring *txr) work += txr->num_desc; txr->next_to_clean = work; + /* + * Queue Hang detection, we know there's + * work outstanding or the first return + * would have been taken, so increment busy + * if nothing managed to get cleaned, then + * in local_timer it will be checked and + * marked as HUNG if it exceeds a MAX attempt. + */ + if ((processed == 0) && (txr->busy != IXGBE_QUEUE_HUNG)) + ++txr->busy; + /* + * If anything gets cleaned we reset state to 1, + * note this will turn off HUNG if its set. + */ + if (processed) + txr->busy = 1; + if (txr->tx_avail == txr->num_desc) - txr->sending = false; + txr->busy = 0; return ((limit > 0) ? false : true); } /* ixgbe_txeof */ Index: src/sys/dev/pci/ixgbe/ixgbe.c diff -u src/sys/dev/pci/ixgbe/ixgbe.c:1.152 src/sys/dev/pci/ixgbe/ixgbe.c:1.153 --- src/sys/dev/pci/ixgbe/ixgbe.c:1.152 Tue May 15 09:30:56 2018 +++ src/sys/dev/pci/ixgbe/ixgbe.c Fri May 18 10:09:02 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: ixgbe.c,v 1.152 2018/05/15 09:30:56 msaitoh Exp $ */ +/* $NetBSD: ixgbe.c,v 1.153 2018/05/18 10:09:02 msaitoh Exp $ */ /****************************************************************************** @@ -184,8 +184,6 @@ static void ixgbe_free_pciintr_resources static void ixgbe_free_pci_resources(struct adapter *); static void ixgbe_local_timer(void *); static void ixgbe_local_timer1(void *); -static void ixgbe_watchdog(struct ifnet *); -static bool ixgbe_watchdog_txq(struct ifnet *, struct tx_ring *, bool *); static int ixgbe_setup_interface(device_t, struct adapter *); static void ixgbe_config_gpie(struct adapter *); static void ixgbe_config_dmac(struct adapter *); @@ -4293,8 +4291,11 @@ static void ixgbe_local_timer1(void *arg) { struct adapter *adapter = arg; + device_t dev = adapter->dev; struct ix_queue *que = adapter->queues; + u64 queues = 0; u64 v0, v1, v2, v3, v4, v5, v6, v7; + int hung = 0; int i; KASSERT(mutex_owned(&adapter->core_mtx)); @@ -4331,93 +4332,63 @@ ixgbe_local_timer1(void *arg) adapter->enomem_tx_dma_setup.ev_count = v6; adapter->tso_err.ev_count = v7; - ixgbe_watchdog(adapter->ifp); - -out: - callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter); -} /* ixgbe_local_timer */ - -static void -ixgbe_watchdog(struct ifnet *ifp) -{ - struct adapter *adapter = ifp->if_softc; - struct ix_queue *que; - struct tx_ring *txr; - u64 queues = 0; - bool hung = false; - bool sending = false; - int i; - - txr = adapter->tx_rings; - for (i = 0; i < adapter->num_queues; i++, txr++) { - hung = ixgbe_watchdog_txq(ifp, txr, &sending); - if (hung) - break; - else if (sending) - queues |= ((u64)1 << txr->me); - } - - if (hung) { - ifp->if_flags &= ~IFF_RUNNING; - ifp->if_oerrors++; - adapter->watchdog_events.ev_count++; - ixgbe_init_locked(adapter); - } else if (queues != 0) { + /* + * Check the TX queues status + * - mark hung queues so we don't schedule on them + * - watchdog only if all queues show hung + */ + que = adapter->queues; + for (i = 0; i < adapter->num_queues; i++, que++) { + /* Keep track of queues with work for soft irq */ + if (que->txr->busy) + queues |= ((u64)1 << que->me); /* - * Force an IRQ on queues with work. - * - * It's supporsed not to be called ixgbe_rearm_queues() if - * any chips have no bug. In reality, ixgbe_rearm_queues() is - * required on 82599 and newer chip AND other than queue 0 to - * prevent device timeout. When it occured, packet was sent but - * the descriptor's DD bot wasn't set even though - * IXGBE_TXD_CMD_EOP and IXGBE_TXD_CMD_RS were set. After - * forcing interrupt by writing EICS register in - * ixgbe_rearm_queues(), DD is set. Why? Is this an - * undocumented errata? It might be possible not call - * rearm_queues on 82598 or queue 0, we call in any cases in - * case the problem occurs. + * Each time txeof runs without cleaning, but there + * are uncleaned descriptors it increments busy. If + * we get to the MAX we declare it hung. */ + if (que->busy == IXGBE_QUEUE_HUNG) { + ++hung; + /* Mark the queue as inactive */ + adapter->active_queues &= ~((u64)1 << que->me); + continue; + } else { + /* Check if we've come back from hung */ + if ((adapter->active_queues & ((u64)1 << que->me)) == 0) + adapter->active_queues |= ((u64)1 << que->me); + } + if (que->busy >= IXGBE_MAX_TX_BUSY) { + device_printf(dev, + "Warning queue %d appears to be hung!\n", i); + que->txr->busy = IXGBE_QUEUE_HUNG; + ++hung; + } + } + + /* Only truely watchdog if all queues show hung */ + if (hung == adapter->num_queues) + goto watchdog; + else if (queues != 0) { /* Force an IRQ on queues with work */ que = adapter->queues; for (i = 0; i < adapter->num_queues; i++, que++) { - u64 index = queues & ((u64)1 << i); - mutex_enter(&que->dc_mtx); - if ((index != 0) && (que->disabled_count == 0)) - ixgbe_rearm_queues(adapter, index); + if (que->disabled_count == 0) + ixgbe_rearm_queues(adapter, + queues & ((u64)1 << i)); mutex_exit(&que->dc_mtx); } } -} - -static bool -ixgbe_watchdog_txq(struct ifnet *ifp, struct tx_ring *txr, bool *sending) -{ - struct adapter *adapter = ifp->if_softc; - device_t dev = adapter->dev; - bool hung = false; - bool more = false; - IXGBE_TX_LOCK(txr); - *sending = txr->sending; - if (*sending && ((time_uptime - txr->lastsent) > IXGBE_TX_TIMEOUT)) { - /* - * Since we're using delayed interrupts, sweep up before we - * report an error. - */ - do { - more = ixgbe_txeof(txr); - } while (more); - hung = true; - device_printf(dev, - "Watchdog timeout (queue %d%s)-- resetting\n", txr->me, - (txr->tx_avail == txr->num_desc) - ? ", lost interrupt?" : ""); - } - IXGBE_TX_UNLOCK(txr); +out: + callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter); + return; - return hung; -} +watchdog: + device_printf(adapter->dev, "Watchdog timeout -- resetting\n"); + adapter->ifp->if_flags &= ~IFF_RUNNING; + adapter->watchdog_events.ev_count++; + ixgbe_init_locked(adapter); +} /* ixgbe_local_timer */ /************************************************************************ * ixgbe_sfp_probe @@ -4577,8 +4548,6 @@ ixgbe_stop(void *arg) struct ifnet *ifp; struct adapter *adapter = arg; struct ixgbe_hw *hw = &adapter->hw; - struct tx_ring *txr; - int i; ifp = adapter->ifp; @@ -4588,13 +4557,6 @@ ixgbe_stop(void *arg) ixgbe_disable_intr(adapter); callout_stop(&adapter->timer); - txr = adapter->tx_rings; - for (i = 0; i < adapter->num_queues; i++, txr++) { - IXGBE_TX_LOCK(txr); - txr->sending = false; - IXGBE_TX_UNLOCK(txr); - } - /* Let the stack know...*/ ifp->if_flags &= ~IFF_RUNNING; @@ -6188,8 +6150,8 @@ static int ixgbe_allocate_msix(struct adapter *adapter, const struct pci_attach_args *pa) { device_t dev = adapter->dev; - struct ix_queue *que = adapter->queues; - struct tx_ring *txr = adapter->tx_rings; + struct ix_queue *que = adapter->queues; + struct tx_ring *txr = adapter->tx_rings; pci_chipset_tag_t pc; char intrbuf[PCI_INTRSTR_LEN]; char intr_xname[32]; @@ -6529,7 +6491,7 @@ ixgbe_handle_link(void *context) /************************************************************************ * ixgbe_rearm_queues ************************************************************************/ -static inline void +static void ixgbe_rearm_queues(struct adapter *adapter, u64 queues) { u32 mask; Index: src/sys/dev/pci/ixgbe/ixgbe.h diff -u src/sys/dev/pci/ixgbe/ixgbe.h:1.47 src/sys/dev/pci/ixgbe/ixgbe.h:1.48 --- src/sys/dev/pci/ixgbe/ixgbe.h:1.47 Tue May 8 09:45:54 2018 +++ src/sys/dev/pci/ixgbe/ixgbe.h Fri May 18 10:09:02 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: ixgbe.h,v 1.47 2018/05/08 09:45:54 msaitoh Exp $ */ +/* $NetBSD: ixgbe.h,v 1.48 2018/05/18 10:09:02 msaitoh Exp $ */ /****************************************************************************** SPDX-License-Identifier: BSD-3-Clause @@ -154,7 +154,7 @@ * pass between any two TX clean operations, such only happening * when the TX hardware is functioning. */ -#define IXGBE_TX_TIMEOUT 10 +#define IXGBE_WATCHDOG (10 * hz) /* * This parameters control when the driver calls the routine to reclaim @@ -219,6 +219,8 @@ #define IXGBE_VFTA_SIZE 128 #define IXGBE_BR_SIZE 4096 #define IXGBE_QUEUE_MIN_FREE 32 +#define IXGBE_MAX_TX_BUSY 10 +#define IXGBE_QUEUE_HUNG 0x80000000 #define IXGBE_EITR_DEFAULT 128 @@ -321,6 +323,7 @@ struct ix_queue { u32 eitr_setting; u32 me; struct resource *res; + int busy; struct tx_ring *txr; struct rx_ring *rxr; struct work wq_cookie; @@ -350,8 +353,7 @@ struct tx_ring { kmutex_t tx_mtx; u32 me; u32 tail; - bool sending; /* enable/disable watchdog */ - time_t lastsent; + int busy; union ixgbe_adv_tx_desc *tx_base; struct ixgbe_tx_buf *tx_buffers; struct ixgbe_dma_alloc txdma; Index: src/sys/dev/pci/ixgbe/ixv.c diff -u src/sys/dev/pci/ixgbe/ixv.c:1.97 src/sys/dev/pci/ixgbe/ixv.c:1.98 --- src/sys/dev/pci/ixgbe/ixv.c:1.97 Mon May 14 09:21:36 2018 +++ src/sys/dev/pci/ixgbe/ixv.c Fri May 18 10:09:02 2018 @@ -1,4 +1,4 @@ -/*$NetBSD: ixv.c,v 1.97 2018/05/14 09:21:36 msaitoh Exp $*/ +/*$NetBSD: ixv.c,v 1.98 2018/05/18 10:09:02 msaitoh Exp $*/ /****************************************************************************** @@ -101,8 +101,6 @@ static int ixv_configure_interrupts static void ixv_free_pci_resources(struct adapter *); static void ixv_local_timer(void *); static void ixv_local_timer_locked(void *); -static void ixv_watchdog(struct ifnet *); -static bool ixv_watchdog_txq(struct ifnet *, struct tx_ring *, bool *); static int ixv_setup_interface(device_t, struct adapter *); static int ixv_negotiate_api(struct adapter *); @@ -1191,8 +1189,11 @@ static void ixv_local_timer_locked(void *arg) { struct adapter *adapter = arg; + device_t dev = adapter->dev; struct ix_queue *que = adapter->queues; + u64 queues = 0; u64 v0, v1, v2, v3, v4, v5, v6, v7; + int hung = 0; int i; KASSERT(mutex_owned(&adapter->core_mtx)); @@ -1226,85 +1227,57 @@ ixv_local_timer_locked(void *arg) adapter->enomem_tx_dma_setup.ev_count = v6; adapter->tso_err.ev_count = v7; - ixv_watchdog(adapter->ifp); - - callout_reset(&adapter->timer, hz, ixv_local_timer, adapter); - - return; -} /* ixv_local_timer */ - -static void -ixv_watchdog(struct ifnet *ifp) -{ - struct adapter *adapter = ifp->if_softc; - struct ix_queue *que; - struct tx_ring *txr; - u64 queues = 0; - bool hung = false; - bool sending = false; - int i; - - txr = adapter->tx_rings; - for (i = 0; i < adapter->num_queues; i++, txr++) { - hung = ixv_watchdog_txq(ifp, txr, &sending); - if (hung) - break; - else if (sending) - queues |= ((u64)1 << txr->me); - } - - if (hung) { - ifp->if_flags &= ~IFF_RUNNING; - ifp->if_oerrors++; - adapter->watchdog_events.ev_count++; - ixv_init_locked(adapter); - } else if (queues != 0) { + /* + * Check the TX queues status + * - mark hung queues so we don't schedule on them + * - watchdog only if all queues show hung + */ + que = adapter->queues; + for (i = 0; i < adapter->num_queues; i++, que++) { + /* Keep track of queues with work for soft irq */ + if (que->txr->busy) + queues |= ((u64)1 << que->me); /* - * Force an IRQ on queues with work - * - * Calling ixv_rearm_queues() might not required. I've never - * seen any device timeout on ixv(4). + * Each time txeof runs without cleaning, but there + * are uncleaned descriptors it increments busy. If + * we get to the MAX we declare it hung. */ - que = adapter->queues; - for (i = 0; i < adapter->num_queues; i++, que++) { - u64 index = queues & ((u64)1 << i); - - mutex_enter(&que->dc_mtx); - if ((index != 0) && (que->disabled_count == 0)) - ixv_rearm_queues(adapter, index); - mutex_exit(&que->dc_mtx); + if (que->busy == IXGBE_QUEUE_HUNG) { + ++hung; + /* Mark the queue as inactive */ + adapter->active_queues &= ~((u64)1 << que->me); + continue; + } else { + /* Check if we've come back from hung */ + if ((adapter->active_queues & ((u64)1 << que->me)) == 0) + adapter->active_queues |= ((u64)1 << que->me); + } + if (que->busy >= IXGBE_MAX_TX_BUSY) { + device_printf(dev, + "Warning queue %d appears to be hung!\n", i); + que->txr->busy = IXGBE_QUEUE_HUNG; + ++hung; } } -} -static bool -ixv_watchdog_txq(struct ifnet *ifp, struct tx_ring *txr, bool *sending) -{ - struct adapter *adapter = ifp->if_softc; - device_t dev = adapter->dev; - bool hung = false; - bool more = false; - - IXGBE_TX_LOCK(txr); - *sending = txr->sending; - if (*sending && ((time_uptime - txr->lastsent) > IXGBE_TX_TIMEOUT)) { - /* - * Since we're using delayed interrupts, sweep up before we - * report an error. - */ - do { - more = ixgbe_txeof(txr); - } while (more); - hung = true; - device_printf(dev, - "Watchdog timeout (queue %d%s)-- resetting\n", txr->me, - (txr->tx_avail == txr->num_desc) - ? ", lost interrupt?" : ""); + /* Only truly watchdog if all queues show hung */ + if (hung == adapter->num_queues) + goto watchdog; + else if (queues != 0) { /* Force an IRQ on queues with work */ + ixv_rearm_queues(adapter, queues); } - IXGBE_TX_UNLOCK(txr); - return hung; -} + callout_reset(&adapter->timer, hz, ixv_local_timer, adapter); + + return; + +watchdog: + + device_printf(adapter->dev, "Watchdog timeout -- resetting\n"); + adapter->ifp->if_flags &= ~IFF_RUNNING; + adapter->watchdog_events.ev_count++; + ixv_init_locked(adapter); +} /* ixv_local_timer */ /************************************************************************ * ixv_update_link_status - Update OS on link state @@ -1388,8 +1361,6 @@ ixv_stop(void *arg) struct ifnet *ifp; struct adapter *adapter = arg; struct ixgbe_hw *hw = &adapter->hw; - struct tx_ring *txr; - int i; ifp = adapter->ifp; @@ -1397,14 +1368,6 @@ ixv_stop(void *arg) INIT_DEBUGOUT("ixv_stop: begin\n"); ixv_disable_intr(adapter); - callout_stop(&adapter->timer); - - txr = adapter->tx_rings; - for (i = 0; i < adapter->num_queues; i++, txr++) { - IXGBE_TX_LOCK(txr); - txr->sending = false; - IXGBE_TX_UNLOCK(txr); - } /* Tell the stack that the interface is no longer active */ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); @@ -1412,6 +1375,7 @@ ixv_stop(void *arg) hw->mac.ops.reset_hw(hw); adapter->hw.adapter_stopped = FALSE; hw->mac.ops.stop_adapter(hw); + callout_stop(&adapter->timer); /* reprogram the RAR[0] in case user changed it. */ hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); @@ -2910,7 +2874,7 @@ ixv_allocate_msix(struct adapter *adapte { device_t dev = adapter->dev; struct ix_queue *que = adapter->queues; - struct tx_ring *txr = adapter->tx_rings; + struct tx_ring *txr = adapter->tx_rings; int error, msix_ctrl, rid, vector = 0; pci_chipset_tag_t pc; pcitag_t tag;