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;

Reply via email to