mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: "Bryan O'Sullivan" <bos@pathscale.com>
To: akpm@osdl.org, rdreier@cisco.com, mst@mellanox.co.il
Cc: openib-general@openib.org, linux-kernel@vger.kernel.org,
	netdev@vger.kernel.org
Subject: [PATCH 20 of 39] IB/ipath - reduce overhead on receive interrupts
Date: Thu, 29 Jun 2006 14:41:11 -0700	[thread overview]
Message-ID: <8bc865893a11e5c8772c.1151617271@eng-12.pathscale.com> (raw)
In-Reply-To: <patchbomb.1151617251@eng-12.pathscale.com>

Also count the number of interrupts where that works (fastrcvint).
On any interrupt where the port0 head and tail registers are not equal,
just call the ipath_kreceive code without reading the interrupt status,
thus saving the approximately 0.25usec processor stall waiting for the
read to return.  If any other interrupt bits are set, or head==tail,
take the normal path, but that has been reordered to handle read ahead
of pioavail.  Also no longer call ipath_kreceive() from ipath_qcheck(),
because that just seems to make things worse, and isn't really buying
us anything, these days.

Also no longer loop in ipath_kreceive(); better to not hold things off
too long (I saw many cases where we would loop 4-8 times, and handle
thousands (up to 3500) in a single call).

Signed-off-by: Dave Olson <dave.olson@qlogic.com>
Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>

diff -r 1e8837473193 -r 8bc865893a11 drivers/infiniband/hw/ipath/ipath_common.h
--- a/drivers/infiniband/hw/ipath/ipath_common.h	Thu Jun 29 14:33:25 2006 -0700
+++ b/drivers/infiniband/hw/ipath/ipath_common.h	Thu Jun 29 14:33:25 2006 -0700
@@ -97,8 +97,8 @@ struct infinipath_stats {
 	__u64 sps_hwerrs;
 	/* number of times IB link changed state unexpectedly */
 	__u64 sps_iblink;
-	/* no longer used; left for compatibility */
-	__u64 sps_unused3;
+	/* kernel receive interrupts that didn't read intstat */
+	__u64 sps_fastrcvint;
 	/* number of kernel (port0) packets received */
 	__u64 sps_port0pkts;
 	/* number of "ethernet" packets sent by driver */
diff -r 1e8837473193 -r 8bc865893a11 drivers/infiniband/hw/ipath/ipath_driver.c
--- a/drivers/infiniband/hw/ipath/ipath_driver.c	Thu Jun 29 14:33:25 2006 -0700
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c	Thu Jun 29 14:33:25 2006 -0700
@@ -888,12 +888,7 @@ void ipath_kreceive(struct ipath_devdata
 	    (u32)le64_to_cpu(*dd->ipath_hdrqtailptr))
 		goto done;
 
-gotmore:
-	/*
-	 * read only once at start.  If in flood situation, this helps
-	 * performance slightly.  If more arrive while we are processing,
-	 * we'll come back here and do them
-	 */
+	/* read only once at start for performance */
 	hdrqtail = (u32)le64_to_cpu(*dd->ipath_hdrqtailptr);
 
 	for (i = 0, l = dd->ipath_port0head; l != hdrqtail; i++) {
@@ -1022,10 +1017,6 @@ gotmore:
 
 	dd->ipath_port0head = l;
 
-	if (hdrqtail != (u32)le64_to_cpu(*dd->ipath_hdrqtailptr))
-		/* more arrived while we handled first batch */
-		goto gotmore;
-
 	if (pkttot > ipath_stats.sps_maxpkts_call)
 		ipath_stats.sps_maxpkts_call = pkttot;
 	ipath_stats.sps_port0pkts += pkttot;
diff -r 1e8837473193 -r 8bc865893a11 drivers/infiniband/hw/ipath/ipath_intr.c
--- a/drivers/infiniband/hw/ipath/ipath_intr.c	Thu Jun 29 14:33:25 2006 -0700
+++ b/drivers/infiniband/hw/ipath/ipath_intr.c	Thu Jun 29 14:33:25 2006 -0700
@@ -539,10 +539,10 @@ static void handle_errors(struct ipath_d
 				continue;
 			if (hd == (tl + 1) ||
 			    (!hd && tl == dd->ipath_hdrqlast)) {
+				if (i == 0)
+					chkerrpkts = 1;
 				dd->ipath_lastrcvhdrqtails[i] = tl;
 				pd->port_hdrqfull++;
-				if (i == 0)
-					chkerrpkts = 1;
 			}
 		}
 	}
@@ -724,7 +724,12 @@ set:
 			 dd->ipath_sendctrl);
 }
 
-static void handle_rcv(struct ipath_devdata *dd, u32 istat)
+/*
+ * Handle receive interrupts for user ports; this means a user
+ * process was waiting for a packet to arrive, and didn't want
+ * to poll
+ */
+static void handle_urcv(struct ipath_devdata *dd, u32 istat)
 {
 	u64 portr;
 	int i;
@@ -734,22 +739,17 @@ static void handle_rcv(struct ipath_devd
 		 infinipath_i_rcvavail_mask)
 		| ((istat >> INFINIPATH_I_RCVURG_SHIFT) &
 		   infinipath_i_rcvurg_mask);
-	for (i = 0; i < dd->ipath_cfgports; i++) {
+	for (i = 1; i < dd->ipath_cfgports; i++) {
 		struct ipath_portdata *pd = dd->ipath_pd[i];
-		if (portr & (1 << i) && pd &&
-		    pd->port_cnt) {
-			if (i == 0)
-				ipath_kreceive(dd);
-			else if (test_bit(IPATH_PORT_WAITING_RCV,
-					  &pd->port_flag)) {
-				int rcbit;
-				clear_bit(IPATH_PORT_WAITING_RCV,
-					  &pd->port_flag);
-				rcbit = i + INFINIPATH_R_INTRAVAIL_SHIFT;
-				clear_bit(1UL << rcbit, &dd->ipath_rcvctrl);
-				wake_up_interruptible(&pd->port_wait);
-				rcvdint = 1;
-			}
+		if (portr & (1 << i) && pd && pd->port_cnt &&
+			test_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag)) {
+			int rcbit;
+			clear_bit(IPATH_PORT_WAITING_RCV,
+				  &pd->port_flag);
+			rcbit = i + INFINIPATH_R_INTRAVAIL_SHIFT;
+			clear_bit(1UL << rcbit, &dd->ipath_rcvctrl);
+			wake_up_interruptible(&pd->port_wait);
+			rcvdint = 1;
 		}
 	}
 	if (rcvdint) {
@@ -767,14 +767,17 @@ irqreturn_t ipath_intr(int irq, void *da
 	struct ipath_devdata *dd = data;
 	u32 istat;
 	ipath_err_t estat = 0;
+	irqreturn_t ret;
+	u32 p0bits;
 	static unsigned unexpected = 0;
-	irqreturn_t ret;
-
-	if(!(dd->ipath_flags & IPATH_PRESENT)) {
-		/* this is mostly so we don't try to touch the chip while
-		 * it is being reset */
-		/*
-		 * This return value is perhaps odd, but we do not want the
+	static const u32 port0rbits = (1U<<INFINIPATH_I_RCVAVAIL_SHIFT) |
+		 (1U<<INFINIPATH_I_RCVURG_SHIFT);
+
+	ipath_stats.sps_ints++;
+
+	if (!(dd->ipath_flags & IPATH_PRESENT)) {
+		/*
+		 * This return value is not great, but we do not want the
 		 * interrupt core code to remove our interrupt handler
 		 * because we don't appear to be handling an interrupt
 		 * during a chip reset.
@@ -782,6 +785,50 @@ irqreturn_t ipath_intr(int irq, void *da
 		return IRQ_HANDLED;
 	}
 
+	/*
+	 * this needs to be flags&initted, not statusp, so we keep
+	 * taking interrupts even after link goes down, etc.
+	 * Also, we *must* clear the interrupt at some point, or we won't
+	 * take it again, which can be real bad for errors, etc...
+	 */
+ 
+	if (!(dd->ipath_flags & IPATH_INITTED)) {
+		ipath_bad_intr(dd, &unexpected);
+		ret = IRQ_NONE;
+		goto bail;
+	}
+ 
+	/*
+	 * We try to avoid reading the interrupt status register, since
+	 * that's a PIO read, and stalls the processor for up to about
+	 * ~0.25 usec. The idea is that if we processed a port0 packet,
+	 * we blindly clear the  port 0 receive interrupt bits, and nothing
+	 * else, then return.  If other interrupts are pending, the chip
+	 * will re-interrupt us as soon as we write the intclear register.
+	 * We then won't process any more kernel packets (if not the 2nd
+	 * time, then the 3rd or 4th) and we'll then handle the other
+	 * interrupts.   We clear the interrupts first so that we don't
+	 * lose intr for later packets that arrive while we are processing.
+	 */
+	if (dd->ipath_port0head !=
+		(u32)le64_to_cpu(*dd->ipath_hdrqtailptr)) {
+		u32 oldhead = dd->ipath_port0head;
+		if (dd->ipath_flags & IPATH_GPIO_INTR) {
+			ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear,
+					 (u64) (1 << 2));
+			p0bits = port0rbits | INFINIPATH_I_GPIO;
+		}
+		else
+			p0bits = port0rbits;
+		ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, p0bits);
+		ipath_kreceive(dd);
+		if (oldhead != dd->ipath_port0head) {
+			ipath_stats.sps_fastrcvint++;
+			goto done;
+		}
+		istat = ipath_read_kreg32(dd, dd->ipath_kregs->kr_intstatus);
+	}
+ 
 	istat = ipath_read_kreg32(dd, dd->ipath_kregs->kr_intstatus);
 	if (unlikely(!istat)) {
 		ipath_stats.sps_nullintr++;
@@ -795,31 +842,17 @@ irqreturn_t ipath_intr(int irq, void *da
 		goto bail;
 	}
 
-	ipath_stats.sps_ints++;
-
-	/*
-	 * this needs to be flags&initted, not statusp, so we keep
-	 * taking interrupts even after link goes down, etc.
-	 * Also, we *must* clear the interrupt at some point, or we won't
-	 * take it again, which can be real bad for errors, etc...
-	 */
-
-	if (!(dd->ipath_flags & IPATH_INITTED)) {
-		ipath_bad_intr(dd, &unexpected);
-		ret = IRQ_NONE;
-		goto bail;
-	}
 	if (unexpected)
 		unexpected = 0;
 
-	ipath_cdbg(VERBOSE, "intr stat=0x%x\n", istat);
-
-	if (istat & ~infinipath_i_bitsextant)
+	if (unlikely(istat & ~infinipath_i_bitsextant))
 		ipath_dev_err(dd,
 			      "interrupt with unknown interrupts %x set\n",
 			      istat & (u32) ~ infinipath_i_bitsextant);
-
-	if (istat & INFINIPATH_I_ERROR) {
+	else
+		ipath_cdbg(VERBOSE, "intr stat=0x%x\n", istat);
+
+	if (unlikely(istat & INFINIPATH_I_ERROR)) {
 		ipath_stats.sps_errints++;
 		estat = ipath_read_kreg64(dd,
 					  dd->ipath_kregs->kr_errorstatus);
@@ -837,7 +870,14 @@ irqreturn_t ipath_intr(int irq, void *da
 			handle_errors(dd, estat);
 	}
 
+	p0bits = port0rbits;
 	if (istat & INFINIPATH_I_GPIO) {
+		/*
+		 * Packets are available in the port 0 rcv queue.
+		 * Eventually this needs to be generalized to check
+		 * IPATH_GPIO_INTR, and the specific GPIO bit, if
+		 * GPIO interrupts are used for anything else.
+		 */
 		if (unlikely(!(dd->ipath_flags & IPATH_GPIO_INTR))) {
 			u32 gpiostatus;
 			gpiostatus = ipath_read_kreg32(
@@ -851,14 +891,7 @@ irqreturn_t ipath_intr(int irq, void *da
 			/* Clear GPIO status bit 2 */
 			ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear,
 					 (u64) (1 << 2));
-
-			/*
-			 * Packets are available in the port 0 rcv queue.
-			 * Eventually this needs to be generalized to check
-			 * IPATH_GPIO_INTR, and the specific GPIO bit, if
-			 * GPIO interrupts are used for anything else.
-			 */
-			ipath_kreceive(dd);
+			p0bits |= INFINIPATH_I_GPIO;
 		}
 	}
 
@@ -871,6 +904,25 @@ irqreturn_t ipath_intr(int irq, void *da
 	 */
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, istat);
 
+	/*
+	 * we check for both transition from empty to non-empty, and urgent
+	 * packets (those with the interrupt bit set in the header), and
+	 * if enabled, the GPIO bit 2 interrupt used for port0 on some
+	 * HT-400 boards.
+	 * Do this before checking for pio buffers available, since
+	 * receives can overflow; piobuf waiters can afford a few
+	 * extra cycles, since they were waiting anyway.
+	 */
+	if (istat & p0bits) {
+		ipath_kreceive(dd);
+		istat &= ~port0rbits;
+	}
+	if (istat & ((infinipath_i_rcvavail_mask <<
+		      INFINIPATH_I_RCVAVAIL_SHIFT)
+		     | (infinipath_i_rcvurg_mask <<
+			INFINIPATH_I_RCVURG_SHIFT)))
+		handle_urcv(dd, istat);
+
 	if (istat & INFINIPATH_I_SPIOBUFAVAIL) {
 		clear_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
 		ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
@@ -882,17 +934,7 @@ irqreturn_t ipath_intr(int irq, void *da
 		handle_layer_pioavail(dd);
 	}
 
-	/*
-	 * we check for both transition from empty to non-empty, and urgent
-	 * packets (those with the interrupt bit set in the header)
-	 */
-
-	if (istat & ((infinipath_i_rcvavail_mask <<
-		      INFINIPATH_I_RCVAVAIL_SHIFT)
-		     | (infinipath_i_rcvurg_mask <<
-			INFINIPATH_I_RCVURG_SHIFT)))
-		handle_rcv(dd, istat);
-
+done:
 	ret = IRQ_HANDLED;
 
 bail:
diff -r 1e8837473193 -r 8bc865893a11 drivers/infiniband/hw/ipath/ipath_stats.c
--- a/drivers/infiniband/hw/ipath/ipath_stats.c	Thu Jun 29 14:33:25 2006 -0700
+++ b/drivers/infiniband/hw/ipath/ipath_stats.c	Thu Jun 29 14:33:25 2006 -0700
@@ -186,7 +186,6 @@ static void ipath_qcheck(struct ipath_de
 				   dd->ipath_port0head,
 				   (unsigned long long)
 				   ipath_stats.sps_port0pkts);
-			ipath_kreceive(dd);
 		}
 		dd->ipath_lastport0rcv_cnt = ipath_stats.sps_port0pkts;
 	}

  parent reply	other threads:[~2006-06-29 21:56 UTC|newest]

Thread overview: 65+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-06-29 21:40 [PATCH 0 of 39] ipath - bug fixes, performance enhancements, and portability improvements Bryan O'Sullivan
2006-06-29 21:40 ` [PATCH 1 of 39] IB/ipath - Name zero counter offsets so it's clear they aren't counters Bryan O'Sullivan
2006-06-29 21:40 ` [PATCH 2 of 39] IB/ipath - update copyrights and other strings to reflect new company name Bryan O'Sullivan
2006-06-29 21:40 ` [PATCH 3 of 39] IB/ipath - Share more common code between RC and UC protocols Bryan O'Sullivan
2006-06-29 21:40 ` [PATCH 4 of 39] IB/ipath - fix an indenting problem Bryan O'Sullivan
2006-06-29 21:40 ` [PATCH 5 of 39] IB/ipath - fix shared receive queues for RC Bryan O'Sullivan
2006-06-29 21:40 ` [PATCH 6 of 39] IB/ipath - Allow diags on any unit Bryan O'Sullivan
2006-06-29 21:40 ` [PATCH 7 of 39] IB/ipath - update some comments and fix typos Bryan O'Sullivan
2006-06-29 21:40 ` [PATCH 8 of 39] IB/ipath - remove some duplicate code Bryan O'Sullivan
2006-06-29 21:41 ` [PATCH 9 of 39] IB/ipath - don't allow resources to be created with illegal values Bryan O'Sullivan
2006-06-29 21:41 ` [PATCH 10 of 39] IB/ipath - fix some memory leaks on failure paths Bryan O'Sullivan
2006-06-29 21:41 ` [PATCH 11 of 39] IB/ipath - return an error for unknown multicast GID Bryan O'Sullivan
2006-06-29 21:41 ` [PATCH 12 of 39] IB/ipath - report correct device identification information in /sys Bryan O'Sullivan
2006-06-29 21:41 ` [PATCH 13 of 39] IB/ipath - enforce device resource limits Bryan O'Sullivan
2006-06-29 21:41 ` [PATCH 14 of 39] IB/ipath - removed unused field ipath_kregvirt from struct ipath_devdata Bryan O'Sullivan
2006-06-29 21:41 ` [PATCH 15 of 39] IB/ipath - print better debug info when handling 32/64-bit DMA mask problems Bryan O'Sullivan
2006-06-29 21:41 ` [PATCH 16 of 39] IB/ipath - enable freeze mode when shutting down device Bryan O'Sullivan
2006-06-29 21:41 ` [PATCH 17 of 39] IB/ipath - use more appropriate gfp flags Bryan O'Sullivan
2006-06-30  0:02   ` Andrew Morton
2006-06-29 21:41 ` [PATCH 18 of 39] IB/ipath - use vmalloc to allocate struct ipath_devdata Bryan O'Sullivan
2006-06-29 21:41 ` [PATCH 19 of 39] IB/ipath - memory management cleanups Bryan O'Sullivan
2006-06-29 21:41 ` Bryan O'Sullivan [this message]
2006-06-29 21:41 ` [PATCH 21 of 39] IB/ipath - fixed bug 9776 for real. The problem was that I was updating Bryan O'Sullivan
2006-06-29 21:41 ` [PATCH 22 of 39] IB/ipath - fix lost interrupts on HT-400 Bryan O'Sullivan
2006-06-29 21:41 ` [PATCH 23 of 39] IB/ipath - disallow send of invalid packet sizes over UD Bryan O'Sullivan
2006-06-29 21:41 ` [PATCH 24 of 39] IB/ipath - don't confuse the max message size with the MTU Bryan O'Sullivan
2006-06-29 21:41 ` [PATCH 25 of 39] IB/ipath - removed redundant statements Bryan O'Sullivan
2006-06-29 21:41 ` [PATCH 26 of 39] IB/ipath - check for valid LID and multicast LIDs Bryan O'Sullivan
2006-06-29 21:41 ` [PATCH 27 of 39] IB/ipath - fixes to performance get counters for IB compliance Bryan O'Sullivan
2006-06-29 21:41 ` [PATCH 28 of 39] IB/ipath - Fixes a bug where our delay for EEPROM no longer works due to compiler reordering Bryan O'Sullivan
2006-06-30  0:07   ` Andrew Morton
2006-06-30 21:08     ` Roland Dreier
2006-06-29 21:41 ` [PATCH 29 of 39] IB/ipath - RC receive interrupt performance changes Bryan O'Sullivan
2006-06-29 21:41 ` [PATCH 30 of 39] IB/ipath - purge sps_lid and sps_mlid arrays Bryan O'Sullivan
2006-06-29 21:41 ` [PATCH 31 of 39] IB/ipath - drop the "stats" sysfs attribute group Bryan O'Sullivan
2006-06-29 21:41 ` [PATCH 32 of 39] IB/ipath - support more models of InfiniPath hardware Bryan O'Sullivan
2006-06-29 21:41 ` [PATCH 33 of 39] IB/ipath - read/write correct sizes through diag interface Bryan O'Sullivan
2006-06-29 21:41 ` [PATCH 34 of 39] IB/ipath - fix a bug that results in addresses near 0 being written via DMA Bryan O'Sullivan
2006-06-29 21:41 ` [PATCH 35 of 39] IB/ipath - remove some #if 0 code related to lockable memory Bryan O'Sullivan
2006-06-29 21:41 ` [PATCH 36 of 39] IB/ipath - Ignore receive queue size if SRQ is specified Bryan O'Sullivan
2006-06-29 21:41 ` [PATCH 37 of 39] IB/ipath - namespace cleanup: replace ips with ipath Bryan O'Sullivan
2006-06-29 21:41 ` [PATCH 38 of 39] IB/ipath - More changes to support InfiniPath on PowerPC 970 systems Bryan O'Sullivan
2006-06-29 21:53   ` David Miller
2006-06-29 22:01     ` Bryan O'Sullivan
2006-06-29 22:04       ` David Miller
2006-07-03 22:25         ` Anton Blanchard
2006-07-04  4:55           ` Michael S. Tsirkin
2006-07-06 22:37   ` Benjamin Herrenschmidt
2006-07-06 23:34     ` Bryan O'Sullivan
2006-07-06 23:39       ` Benjamin Herrenschmidt
2006-06-29 21:41 ` [PATCH 39 of 39] IB/ipath - use streaming copy in RDMA interrupt handler to reduce packet loss Bryan O'Sullivan
2006-06-29 21:50   ` David Miller
2006-06-29 21:59     ` Bryan O'Sullivan
2006-06-29 22:03       ` David Miller
2006-06-29 23:34         ` Bryan O'Sullivan
2006-06-29 23:46           ` David Miller
2006-06-29 23:55             ` [openib-general] " Ralph Campbell
2006-06-30  0:28             ` Rick Jones
2006-06-30  0:32               ` David Miller
2006-06-30  0:44                 ` Rick Jones
2006-06-30  0:47                   ` David Miller
2006-06-30 16:31 ` [PATCH 0 of 39] ipath - bug fixes, performance enhancements,and portability improvements Michael S. Tsirkin
2006-06-30 17:00   ` Bryan O'Sullivan
2006-07-01 19:43     ` [PATCH 0 of 39] ipath - bug fixes, performanceenhancements,and " Michael S. Tsirkin
2006-07-01 22:35       ` Andrew Morton

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=8bc865893a11e5c8772c.1151617271@eng-12.pathscale.com \
    --to=bos@pathscale.com \
    --cc=akpm@osdl.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mst@mellanox.co.il \
    --cc=netdev@vger.kernel.org \
    --cc=openib-general@openib.org \
    --cc=rdreier@cisco.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome