From aceb0403766778cef4c7f113016db04671314ab8 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Wed, 26 Sep 2012 18:11:43 +0000 Subject: [PATCH] Merge similar fixes from 223198 from igb to ixgbe: - 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 and lock contention. - Don't define ixgbe_start() at all where if_transmit is used. Tested by: Vijay Singh Reviewed by: jfv MFC after: 2 weeks --- sys/dev/e1000/if_igb.h | 2 +- sys/dev/ixgbe/ixgbe.c | 50 +++++++++++++++++++++++++++++++++++------- sys/dev/ixgbe/ixgbe.h | 1 + 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/sys/dev/e1000/if_igb.h b/sys/dev/e1000/if_igb.h index 2be0b08736b..f286e67a9ee 100644 --- a/sys/dev/e1000/if_igb.h +++ b/sys/dev/e1000/if_igb.h @@ -299,9 +299,9 @@ struct tx_ring { struct igb_tx_buffer *tx_buffers; #if __FreeBSD_version >= 800000 struct buf_ring *br; + struct task txq_task; #endif bus_dma_tag_t txtag; - struct task txq_task; u32 bytes; u32 packets; diff --git a/sys/dev/ixgbe/ixgbe.c b/sys/dev/ixgbe/ixgbe.c index 4cf0b38885f..acf4ba2546e 100644 --- a/sys/dev/ixgbe/ixgbe.c +++ b/sys/dev/ixgbe/ixgbe.c @@ -104,13 +104,15 @@ static int ixgbe_probe(device_t); static int ixgbe_attach(device_t); static int ixgbe_detach(device_t); static int ixgbe_shutdown(device_t); -static void ixgbe_start(struct ifnet *); -static void ixgbe_start_locked(struct tx_ring *, struct ifnet *); #if __FreeBSD_version >= 800000 static int ixgbe_mq_start(struct ifnet *, struct mbuf *); static int ixgbe_mq_start_locked(struct ifnet *, struct tx_ring *, struct mbuf *); static void ixgbe_qflush(struct ifnet *); +static void ixgbe_deferred_mq_start(void *, int); +#else +static void ixgbe_start(struct ifnet *); +static void ixgbe_start_locked(struct tx_ring *, struct ifnet *); #endif static int ixgbe_ioctl(struct ifnet *, u_long, caddr_t); static void ixgbe_init(void *); @@ -631,6 +633,7 @@ ixgbe_detach(device_t dev) { struct adapter *adapter = device_get_softc(dev); struct ix_queue *que = adapter->queues; + struct tx_ring *txr = adapter->tx_rings; u32 ctrl_ext; INIT_DEBUGOUT("ixgbe_detach: begin"); @@ -645,8 +648,11 @@ ixgbe_detach(device_t dev) ixgbe_stop(adapter); IXGBE_CORE_UNLOCK(adapter); - for (int i = 0; i < adapter->num_queues; i++, que++) { + for (int i = 0; i < adapter->num_queues; i++, que++, txr++) { if (que->tq) { +#if __FreeBSD_version >= 800000 + taskqueue_drain(que->tq, &txr->txq_task); +#endif taskqueue_drain(que->tq, &que->que_task); taskqueue_free(que->tq); } @@ -708,6 +714,7 @@ ixgbe_shutdown(device_t dev) } +#if __FreeBSD_version < 800000 /********************************************************************* * Transmit entry point * @@ -779,7 +786,7 @@ ixgbe_start(struct ifnet *ifp) return; } -#if __FreeBSD_version >= 800000 +#else /* ** Multiqueue Transmit driver ** @@ -807,7 +814,7 @@ ixgbe_mq_start(struct ifnet *ifp, struct mbuf *m) IXGBE_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); @@ -872,6 +879,22 @@ ixgbe_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 +ixgbe_deferred_mq_start(void *arg, int pending) +{ + struct tx_ring *txr = arg; + struct adapter *adapter = txr->adapter; + struct ifnet *ifp = adapter->ifp; + + IXGBE_TX_LOCK(txr); + if (!drbr_empty(ifp, txr->br)) + ixgbe_mq_start_locked(ifp, txr, NULL); + IXGBE_TX_UNLOCK(txr); +} + /* ** Flush all ring buffers */ @@ -2230,6 +2253,9 @@ ixgbe_allocate_legacy(struct adapter *adapter) { device_t dev = adapter->dev; struct ix_queue *que = adapter->queues; +#if __FreeBSD_version >= 800000 + struct tx_ring *txr = adapter->tx_rings; +#endif int error, rid = 0; /* MSI RID at 1 */ @@ -2249,6 +2275,9 @@ ixgbe_allocate_legacy(struct adapter *adapter) * Try allocating a fast interrupt and the associated deferred * processing contexts. */ +#if __FreeBSD_version >= 800000 + TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr); +#endif TASK_INIT(&que->que_task, 0, ixgbe_handle_que, que); que->tq = taskqueue_create_fast("ixgbe_que", M_NOWAIT, taskqueue_thread_enqueue, &que->tq); @@ -2295,9 +2324,10 @@ ixgbe_allocate_msix(struct adapter *adapter) { device_t dev = adapter->dev; struct ix_queue *que = adapter->queues; + struct tx_ring *txr = adapter->tx_rings; int error, rid, vector = 0; - for (int i = 0; i < adapter->num_queues; i++, vector++, que++) { + for (int i = 0; i < adapter->num_queues; i++, vector++, que++, txr++) { rid = vector + 1; que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); @@ -2327,6 +2357,9 @@ ixgbe_allocate_msix(struct adapter *adapter) if (adapter->num_queues > 1) bus_bind_intr(dev, que->res, i); +#if __FreeBSD_version >= 800000 + TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr); +#endif TASK_INIT(&que->que_task, 0, ixgbe_handle_que, que); que->tq = taskqueue_create_fast("ixgbe_que", M_NOWAIT, taskqueue_thread_enqueue, &que->tq); @@ -2570,12 +2603,13 @@ ixgbe_setup_interface(device_t dev, struct adapter *adapter) ifp->if_softc = adapter; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = ixgbe_ioctl; - ifp->if_start = ixgbe_start; #if __FreeBSD_version >= 800000 ifp->if_transmit = ixgbe_mq_start; ifp->if_qflush = ixgbe_qflush; +#else + ifp->if_start = ixgbe_start; + IFQ_SET_MAXLEN(&ifp->if_snd, adapter->num_tx_desc - 2); #endif - ifp->if_snd.ifq_maxlen = adapter->num_tx_desc - 2; ether_ifattach(ifp, adapter->hw.mac.addr); diff --git a/sys/dev/ixgbe/ixgbe.h b/sys/dev/ixgbe/ixgbe.h index d167306172f..f2b40dfccc4 100644 --- a/sys/dev/ixgbe/ixgbe.h +++ b/sys/dev/ixgbe/ixgbe.h @@ -314,6 +314,7 @@ struct tx_ring { char mtx_name[16]; #if __FreeBSD_version >= 800000 struct buf_ring *br; + struct task txq_task; #endif #ifdef IXGBE_FDIR u16 atr_sample; -- 2.45.2