changeset 9883:0ced6e024277

6839845 ixgbe TX causes huge out of order packets on RX side
author Rajagopal Kunhappan <Rajagopal.Kunhappan@Sun.COM>
date Tue, 16 Jun 2009 12:02:30 -0700
parents a28e5f02b7fa
children 81f4d72ae348
files usr/src/uts/common/inet/ip.h usr/src/uts/common/inet/squeue.c usr/src/uts/common/io/mac/mac_soft_ring.c usr/src/uts/common/sys/mac_soft_ring.h
diffstat 4 files changed, 37 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/inet/ip.h	Tue Jun 16 11:57:32 2009 -0700
+++ b/usr/src/uts/common/inet/ip.h	Tue Jun 16 12:02:30 2009 -0700
@@ -3612,7 +3612,7 @@
  * we need to duplicate the definitions here because we cannot
  * include mac/dls header files here.
  */
-typedef void			(*ip_mac_intr_disable_t)(void *);
+typedef boolean_t		(*ip_mac_intr_disable_t)(void *);
 typedef void			(*ip_mac_intr_enable_t)(void *);
 typedef ip_mac_tx_cookie_t	(*ip_dld_tx_t)(void *, mblk_t *,
     uint64_t, uint16_t);
--- a/usr/src/uts/common/inet/squeue.c	Tue Jun 16 11:57:32 2009 -0700
+++ b/usr/src/uts/common/inet/squeue.c	Tue Jun 16 12:02:30 2009 -0700
@@ -163,14 +163,21 @@
 								\
 }
 
+/*
+ * Blank the receive ring (in this case it is the soft ring). When
+ * blanked, the soft ring will not send any more packets up.
+ * Blanking may not succeed when there is a CPU already in the soft
+ * ring sending packets up. In that case, SQS_POLLING will not be
+ * set.
+ */
 #define	SQS_POLLING_ON(sqp, sq_poll_capable, rx_ring) {		\
 	ASSERT(MUTEX_HELD(&(sqp)->sq_lock));			\
 	if (sq_poll_capable) {					\
 		ASSERT(rx_ring != NULL);			\
 		ASSERT(sqp->sq_state & SQS_POLL_CAPAB);		\
 		if (!(sqp->sq_state & SQS_POLLING)) {		\
-			sqp->sq_state |= SQS_POLLING;		\
-			rx_ring->rr_intr_disable(rx_ring->rr_intr_handle); \
+			if (rx_ring->rr_intr_disable(rx_ring->rr_intr_handle)) \
+				sqp->sq_state |= SQS_POLLING;	\
 		}						\
 	}							\
 }
@@ -187,9 +194,10 @@
 	}							\
 }
 
-#define	SQS_POLL_RING(sqp, sq_poll_capable) {			\
+/* Wakeup poll thread only if SQS_POLLING is set */
+#define	SQS_POLL_RING(sqp) {			\
 	ASSERT(MUTEX_HELD(&(sqp)->sq_lock));			\
-	if (sq_poll_capable) {					\
+	if (sqp->sq_state & SQS_POLLING) {			\
 		ASSERT(sqp->sq_state & SQS_POLL_CAPAB);		\
 		if (!(sqp->sq_state & SQS_GET_PKTS)) {		\
 			sqp->sq_state |= SQS_GET_PKTS;		\
@@ -662,7 +670,6 @@
 
 	sqp->sq_state |= SQS_PROC | proc_type;
 
-
 	/*
 	 * We have backlog built up. Switch to polling mode if the
 	 * device underneath allows it. Need to do it so that
@@ -740,9 +747,14 @@
 			 * We turn off interrupts for all userland threads
 			 * doing drain but we do active polling only for
 			 * worker thread.
+			 *
+			 * Calling SQS_POLL_RING() even in the case of
+			 * SQS_POLLING_ON() not succeeding is ok as
+			 * SQS_POLL_RING() will not wake up poll thread
+			 * if SQS_POLLING bit is not set.
 			 */
 			if (proc_type == SQS_WORKER)
-				SQS_POLL_RING(sqp, sq_poll_capable);
+				SQS_POLL_RING(sqp);
 			goto again;
 		} else {
 			did_wakeup = B_TRUE;
@@ -769,8 +781,7 @@
 	 * thread down once more to see if something arrived. Otherwise,
 	 * turn the interrupts back on and we are done.
 	 */
-	if ((proc_type == SQS_WORKER) &&
-	    (sqp->sq_state & SQS_POLL_CAPAB)) {
+	if ((proc_type == SQS_WORKER) && (sqp->sq_state & SQS_POLLING)) {
 		/*
 		 * Do one last check to see if anything arrived
 		 * in the NIC. We leave the SQS_PROC set to ensure
@@ -792,16 +803,17 @@
 		 */
 		ASSERT(!(sqp->sq_state & (SQS_POLL_THR_QUIESCED |
 		    SQS_POLL_QUIESCE_DONE)));
-		SQS_POLL_RING(sqp, sq_poll_capable);
+		SQS_POLL_RING(sqp);
 		sqp->sq_state &= ~proc_type;
 	} else {
 		/*
-		 * The squeue is either not capable of polling or
-		 * poll thread already finished processing and didn't
-		 * find anything. Since there is nothing queued and
-		 * we already turn polling on (for all threads doing
-		 * drain), we should turn polling off and relinquish
-		 * the PROC.
+		 * The squeue is either not capable of polling or the
+		 * attempt to blank (i.e., turn SQS_POLLING_ON()) was
+		 * unsuccessful or poll thread already finished
+		 * processing and didn't find anything. Since there
+		 * is nothing queued and we already turn polling on
+		 * (for all threads doing drain), we should turn
+		 * polling off and relinquish the PROC.
 		 */
 		ASSERT(!(sqp->sq_state & (SQS_POLL_THR_QUIESCED |
 		    SQS_POLL_QUIESCE_DONE)));
--- a/usr/src/uts/common/io/mac/mac_soft_ring.c	Tue Jun 16 11:57:32 2009 -0700
+++ b/usr/src/uts/common/io/mac/mac_soft_ring.c	Tue Jun 16 12:02:30 2009 -0700
@@ -423,7 +423,7 @@
 start:
 	for (;;) {
 		while (((ringp->s_ring_first == NULL ||
-		    (ringp->s_ring_state & S_RING_BLOCK)) &&
+		    (ringp->s_ring_state & (S_RING_BLOCK|S_RING_BLANK))) &&
 		    !(ringp->s_ring_state & S_RING_PAUSE)) ||
 		    (ringp->s_ring_state & S_RING_PROC)) {
 
@@ -498,17 +498,22 @@
 	mutex_exit(&ringp->s_ring_lock);
 }
 
-void
+boolean_t
 mac_soft_ring_intr_disable(void *arg)
 {
 	mac_soft_ring_t *ringp = (mac_soft_ring_t *)arg;
+	boolean_t sring_blanked = B_FALSE;
 	/*
 	 * Stop worker thread from sending packets above.
 	 * Squeue will poll soft ring when it needs packets.
 	 */
 	mutex_enter(&ringp->s_ring_lock);
-	ringp->s_ring_state |= S_RING_BLANK;
+	if (!(ringp->s_ring_state & S_RING_PROC)) {
+		ringp->s_ring_state |= S_RING_BLANK;
+		sring_blanked = B_TRUE;
+	}
 	mutex_exit(&ringp->s_ring_lock);
+	return (sring_blanked);
 }
 
 /*
--- a/usr/src/uts/common/sys/mac_soft_ring.h	Tue Jun 16 11:57:32 2009 -0700
+++ b/usr/src/uts/common/sys/mac_soft_ring.h	Tue Jun 16 12:02:30 2009 -0700
@@ -691,7 +691,7 @@
 extern void mac_client_update_classifier(mac_client_impl_t *, boolean_t);
 
 extern void mac_soft_ring_intr_enable(void *);
-extern void mac_soft_ring_intr_disable(void *);
+extern boolean_t mac_soft_ring_intr_disable(void *);
 extern mac_soft_ring_t *mac_soft_ring_create(int, clock_t, void *, uint16_t,
     pri_t, mac_client_impl_t *, mac_soft_ring_set_t *,
     processorid_t, mac_direct_rx_t, void *, mac_resource_handle_t);