ixgbe rx & tx locks
John Baldwin
jhb at freebsd.org
Wed Sep 26 13:53:32 UTC 2012
On Tuesday, September 25, 2012 4:19:01 pm Vijay Singh wrote:
> > Vijay, can you test this to see if it helps with your test case?
> >
> >> Jack
>
> John, apologies for the delay. I have some data to share now.
>
> With your patch, the transmit side lock contention is all gone.
> However I still see receive side contention. I have MSI/X enabled,
> with one hw queue per-port.
Well, that's progress at least. Jack, can you ok this patch? It is just the
changes to adjust the deferred tx handling and doesn't include any watchdog
changes. The igb fix is just a comestic nit:
Index: dev/e1000/if_igb.h
===================================================================
--- dev/e1000/if_igb.h (revision 240960)
+++ dev/e1000/if_igb.h (working copy)
@@ -299,9 +299,9 @@
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;
Index: dev/ixgbe/ixgbe.c
===================================================================
--- dev/ixgbe/ixgbe.c (revision 240960)
+++ dev/ixgbe/ixgbe.c (working copy)
@@ -104,13 +104,15 @@
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 @@
{
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_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 @@
}
+#if __FreeBSD_version < 800000
/*********************************************************************
* Transmit entry point
*
@@ -779,7 +786,7 @@
return;
}
-#if __FreeBSD_version >= 800000
+#else
/*
** Multiqueue Transmit driver
**
@@ -807,7 +814,7 @@
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);
@@ -873,6 +880,22 @@
}
/*
+ * 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
*/
static void
@@ -2230,6 +2258,9 @@
{
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 +2280,9 @@
* 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 +2329,10 @@
{
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 +2362,9 @@
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 +2608,13 @@
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);
Index: dev/ixgbe/ixgbe.h
===================================================================
--- dev/ixgbe/ixgbe.h (revision 240960)
+++ dev/ixgbe/ixgbe.h (working copy)
@@ -314,6 +314,7 @@
char mtx_name[16];
#if __FreeBSD_version >= 800000
struct buf_ring *br;
+ struct task txq_task;
#endif
#ifdef IXGBE_FDIR
u16 atr_sample;
--
John Baldwin
More information about the freebsd-net
mailing list