Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 29 Jun 2011 16:16:59 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r223675 - stable/8/sys/dev/e1000
Message-ID:  <201106291616.p5TGGxOn004729@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhb
Date: Wed Jun 29 16:16:59 2011
New Revision: 223675
URL: http://svn.freebsd.org/changeset/base/223675

Log:
  MFC 223198:
  - Use a dedicated task to handle deferred transmits from the if_transmit
    method instead of reusing the existing per-queue interrupt task.
    Reusing the per-queue interrupt task could result in both an interrupt
    thread and the taskqueue thread trying to handle received packets on a
    single queue resulting in out-of-order packet processing.
  - Don't define igb_start() at all on 8.0 and where if_transmit is used.
    Replace last remaining call to igb_start() with a loop to kick off
    transmit on each queue instead.
  - Call ether_ifdetach() earlier in igb_detach().
  - Drain tasks and free taskqueues during igb_detach().

Modified:
  stable/8/sys/dev/e1000/if_igb.c
  stable/8/sys/dev/e1000/if_igb.h
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)

Modified: stable/8/sys/dev/e1000/if_igb.c
==============================================================================
--- stable/8/sys/dev/e1000/if_igb.c	Wed Jun 29 15:58:26 2011	(r223674)
+++ stable/8/sys/dev/e1000/if_igb.c	Wed Jun 29 16:16:59 2011	(r223675)
@@ -170,13 +170,15 @@ static int	igb_detach(device_t);
 static int	igb_shutdown(device_t);
 static int	igb_suspend(device_t);
 static int	igb_resume(device_t);
-static void	igb_start(struct ifnet *);
-static void	igb_start_locked(struct tx_ring *, struct ifnet *ifp);
 #if __FreeBSD_version >= 800000
 static int	igb_mq_start(struct ifnet *, struct mbuf *);
 static int	igb_mq_start_locked(struct ifnet *,
 		    struct tx_ring *, struct mbuf *);
 static void	igb_qflush(struct ifnet *);
+static void	igb_deferred_mq_start(void *, int);
+#else
+static void	igb_start(struct ifnet *);
+static void	igb_start_locked(struct tx_ring *, struct ifnet *ifp);
 #endif
 static int	igb_ioctl(struct ifnet *, u_long, caddr_t);
 static void	igb_init(void *);
@@ -693,6 +695,8 @@ igb_detach(device_t dev)
 		return (EBUSY);
 	}
 
+	ether_ifdetach(adapter->ifp);
+
 	if (adapter->led_dev != NULL)
 		led_destroy(adapter->led_dev);
 
@@ -724,8 +728,6 @@ igb_detach(device_t dev)
 	if (adapter->vlan_detach != NULL)
 		EVENTHANDLER_DEREGISTER(vlan_unconfig, adapter->vlan_detach);
 
-	ether_ifdetach(adapter->ifp);
-
 	callout_drain(&adapter->timer);
 
 	igb_free_pci_resources(adapter);
@@ -784,14 +786,27 @@ igb_resume(device_t dev)
 {
 	struct adapter *adapter = device_get_softc(dev);
 	struct ifnet *ifp = adapter->ifp;
+#if __FreeBSD_version >= 800000
+	struct tx_ring *txr = adapter->tx_rings;
+#endif
 
 	IGB_CORE_LOCK(adapter);
 	igb_init_locked(adapter);
 	igb_init_manageability(adapter);
 
 	if ((ifp->if_flags & IFF_UP) &&
-	    (ifp->if_drv_flags & IFF_DRV_RUNNING))
+	    (ifp->if_drv_flags & IFF_DRV_RUNNING)) {
+#if __FreeBSD_version < 800000
 		igb_start(ifp);
+#else
+		for (int i = 0; i < adapter->num_queues; i++, txr++) {
+			IGB_TX_LOCK(txr);
+			if (!drbr_empty(ifp, txr->br))
+				igb_mq_start_locked(ifp, txr, NULL);
+			IGB_TX_UNLOCK(txr);
+		}
+#endif
+	}
 
 	IGB_CORE_UNLOCK(adapter);
 
@@ -799,6 +814,7 @@ igb_resume(device_t dev)
 }
 
 
+#if __FreeBSD_version < 800000
 /*********************************************************************
  *  Transmit entry point
  *
@@ -875,7 +891,7 @@ igb_start(struct ifnet *ifp)
 	return;
 }
 
-#if __FreeBSD_version >= 800000
+#else /* __FreeBSD_version >= 800000 */
 /*
 ** Multiqueue Transmit driver
 **
@@ -900,7 +916,7 @@ igb_mq_start(struct ifnet *ifp, struct m
 		IGB_TX_UNLOCK(txr);
 	} else {
 		err = drbr_enqueue(ifp, txr->br, m);
-		taskqueue_enqueue(que->tq, &que->que_task);
+		taskqueue_enqueue(que->tq, &txr->txq_task);
 	}
 
 	return (err);
@@ -961,6 +977,22 @@ igb_mq_start_locked(struct ifnet *ifp, s
 }
 
 /*
+ * Called from a taskqueue to drain queued transmit packets.
+ */
+static void
+igb_deferred_mq_start(void *arg, int pending)
+{
+	struct tx_ring *txr = arg;
+	struct adapter *adapter = txr->adapter;
+	struct ifnet *ifp = adapter->ifp;
+
+	IGB_TX_LOCK(txr);
+	if (!drbr_empty(ifp, txr->br))
+		igb_mq_start_locked(ifp, txr, NULL);
+	IGB_TX_UNLOCK(txr);
+}
+
+/*
 ** Flush all ring buffers
 */
 static void
@@ -978,7 +1010,7 @@ igb_qflush(struct ifnet *ifp)
 	}
 	if_qflush(ifp);
 }
-#endif /* __FreeBSD_version >= 800000 */
+#endif /* __FreeBSD_version < 800000 */
 
 /*********************************************************************
  *  Ioctl entry point
@@ -2180,6 +2212,7 @@ igb_allocate_legacy(struct adapter *adap
 {
 	device_t		dev = adapter->dev;
 	struct igb_queue	*que = adapter->queues;
+	struct tx_ring		*txr = adapter->tx_rings;
 	int			error, rid = 0;
 
 	/* Turn off all interrupts */
@@ -2198,6 +2231,10 @@ igb_allocate_legacy(struct adapter *adap
 		return (ENXIO);
 	}
 
+#if __FreeBSD_version >= 800000
+	TASK_INIT(&txr->txq_task, 0, igb_deferred_mq_start, txr);
+#endif
+
 	/*
 	 * Try allocating a fast interrupt and the associated deferred
 	 * processing contexts.
@@ -2268,9 +2305,13 @@ igb_allocate_msix(struct adapter *adapte
 		*/
 		if (adapter->num_queues > 1)
 			bus_bind_intr(dev, que->res, i);
+#if __FreeBSD_version >= 800000
+		TASK_INIT(&que->txr->txq_task, 0, igb_deferred_mq_start,
+		    que->txr);
+#endif
 		/* Make tasklet for deferred handling */
 		TASK_INIT(&que->que_task, 0, igb_handle_que, que);
-		que->tq = taskqueue_create_fast("igb_que", M_NOWAIT,
+		que->tq = taskqueue_create("igb_que", M_NOWAIT,
 		    taskqueue_thread_enqueue, &que->tq);
 		taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que",
 		    device_get_nameunit(adapter->dev));
@@ -2477,13 +2518,24 @@ igb_free_pci_resources(struct adapter *a
 	else
 		(adapter->msix != 0) ? (rid = 1):(rid = 0);
 
+	que = adapter->queues;
 	if (adapter->tag != NULL) {
+		taskqueue_drain(que->tq, &adapter->link_task);
 		bus_teardown_intr(dev, adapter->res, adapter->tag);
 		adapter->tag = NULL;
 	}
 	if (adapter->res != NULL)
 		bus_release_resource(dev, SYS_RES_IRQ, rid, adapter->res);
 
+	for (int i = 0; i < adapter->num_queues; i++, que++) {
+		if (que->tq != NULL) {
+#if __FreeBSD_version >= 800000
+			taskqueue_drain(que->tq, &que->txr->txq_task);
+#endif
+			taskqueue_drain(que->tq, &que->que_task);
+			taskqueue_free(que->tq);
+		}
+	}
 mem:
 	if (adapter->msix)
 		pci_release_msi(dev);
@@ -2744,10 +2796,11 @@ igb_setup_interface(device_t dev, struct
 	ifp->if_softc = adapter;
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
 	ifp->if_ioctl = igb_ioctl;
-	ifp->if_start = igb_start;
 #if __FreeBSD_version >= 800000
 	ifp->if_transmit = igb_mq_start;
 	ifp->if_qflush = igb_qflush;
+#else
+	ifp->if_start = igb_start;
 #endif
 	IFQ_SET_MAXLEN(&ifp->if_snd, adapter->num_tx_desc - 1);
 	ifp->if_snd.ifq_drv_maxlen = adapter->num_tx_desc - 1;

Modified: stable/8/sys/dev/e1000/if_igb.h
==============================================================================
--- stable/8/sys/dev/e1000/if_igb.h	Wed Jun 29 15:58:26 2011	(r223674)
+++ stable/8/sys/dev/e1000/if_igb.h	Wed Jun 29 16:16:59 2011	(r223675)
@@ -297,6 +297,7 @@ struct tx_ring {
 	struct buf_ring		*br;
 #endif
 	bus_dma_tag_t		txtag;
+	struct task		txq_task;
 
 	u32			bytes;
 	u32			packets;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201106291616.p5TGGxOn004729>