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
This commit is contained in:
John Baldwin 2012-04-11 21:33:45 +00:00
parent 45b516f642
commit 8546e82467
2 changed files with 42 additions and 4 deletions

View File

@ -176,6 +176,7 @@ 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);
@ -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 mbuf *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);
@ -1002,6 +1003,22 @@ igb_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr, struct mbuf *m)
return (err);
}
/*
* 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
*/
@ -2382,6 +2399,7 @@ igb_allocate_legacy(struct adapter *adapter)
{
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 *adapter)
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 *adapter)
*/
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 *adapter)
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);

View File

@ -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;