Author: jhb
Date: Wed Apr 11 21:33:45 2012
New Revision: 234154
URL: http://svn.freebsd.org/changeset/base/234154

Log:
  Reapply r223198 which was reverted in the previous vendor import.  Some
  portions were already reapplied in r233708:
  - 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.
  - Call ether_ifdetach() earlier in igb_detach().
  - Drain tasks and free taskqueues during igb_detach().
  
  MFC after:    1 week

Modified:
  head/sys/dev/e1000/if_igb.c
  head/sys/dev/e1000/if_igb.h

Modified: head/sys/dev/e1000/if_igb.c
==============================================================================
--- head/sys/dev/e1000/if_igb.c Wed Apr 11 21:00:33 2012        (r234153)
+++ head/sys/dev/e1000/if_igb.c Wed Apr 11 21:33:45 2012        (r234154)
@@ -176,6 +176,7 @@ static int  igb_mq_start(struct ifnet *, 
 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);
@@ -715,6 +716,8 @@ igb_detach(device_t dev)
                return (EBUSY);
        }
 
+       ether_ifdetach(adapter->ifp);
+
        if (adapter->led_dev != NULL)
                led_destroy(adapter->led_dev);
 
@@ -746,8 +749,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);
 
 #ifdef DEV_NETMAP
@@ -943,7 +944,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);
@@ -1003,6 +1004,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
@@ -2382,6 +2399,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 */
@@ -2400,6 +2418,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.
@@ -2473,9 +2495,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));
@@ -2682,13 +2708,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);

Modified: head/sys/dev/e1000/if_igb.h
==============================================================================
--- head/sys/dev/e1000/if_igb.h Wed Apr 11 21:00:33 2012        (r234153)
+++ head/sys/dev/e1000/if_igb.h Wed Apr 11 21:33:45 2012        (r234154)
@@ -301,6 +301,7 @@ struct tx_ring {
        struct buf_ring         *br;
 #endif
        bus_dma_tag_t           txtag;
+       struct task             txq_task;
 
        u32                     bytes;
        u32                     packets;
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to