Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 27 Oct 2010 23:18:25 +0000 (UTC)
From:      Jeff Roberson <jeff@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r214435 - in projects/ofed/head/sys: kern ofed/include/linux sys
Message-ID:  <201010272318.o9RNIPAT043359@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jeff
Date: Wed Oct 27 23:18:25 2010
New Revision: 214435
URL: http://svn.freebsd.org/changeset/base/214435

Log:
   - Add intr_drain(), a mechanism to wait for any interrupt handlers
     currently running on an ithread to complete.  This is used to
     synchronize the release of state that may be accessed by interrupt
     context.
   - Use intr_drain() in synchronize_irq().
  
  Discussed with:	jhb
  Sponsored by:	Isilon Systems, iX Systems, and Panasas.

Modified:
  projects/ofed/head/sys/kern/kern_intr.c
  projects/ofed/head/sys/ofed/include/linux/hardirq.h
  projects/ofed/head/sys/sys/interrupt.h

Modified: projects/ofed/head/sys/kern/kern_intr.c
==============================================================================
--- projects/ofed/head/sys/kern/kern_intr.c	Wed Oct 27 21:01:53 2010	(r214434)
+++ projects/ofed/head/sys/kern/kern_intr.c	Wed Oct 27 23:18:25 2010	(r214435)
@@ -74,6 +74,7 @@ struct intr_thread {
 
 /* Interrupt thread flags kept in it_flags */
 #define	IT_DEAD		0x000001	/* Thread is waiting to exit. */
+#define	IT_WAIT		0x000001	/* Thread is waiting for completion. */
 
 struct	intr_entropy {
 	struct	thread *td;
@@ -739,6 +740,38 @@ intr_handler_source(void *cookie)
 	return (ie->ie_source);
 }
 
+/*
+ * Sleep until an ithread finishes executing an interrupt handler.
+ *
+ * XXX Doesn't currently handle interrupt filters or fast interrupt
+ * handlers.
+ */
+void
+intr_drain(int irq)
+{
+	struct mtx *mtx;
+	struct intr_event *ie;
+	struct intr_thread *ithd;
+	struct thread *td;
+
+	ie = intr_lookup(irq);
+	if (ie == NULL)
+		return;
+	if (ie->ie_thread == NULL)
+		return;
+	ithd = ie->ie_thread;
+	td = ithd->it_thread;
+	thread_lock(td);
+	mtx = td->td_lock;
+	if (!TD_AWAITING_INTR(td)) {
+		ithd->it_flags |= IT_WAIT;
+		msleep_spin(ithd, mtx, "isync", 0);
+	}
+	mtx_unlock_spin(mtx);
+	return;
+}
+
+
 #ifndef INTR_FILTER
 int
 intr_event_remove_handler(void *cookie)
@@ -1275,6 +1308,7 @@ ithread_loop(void *arg)
 	struct intr_event *ie;
 	struct thread *td;
 	struct proc *p;
+	int wake;
 
 	td = curthread;
 	p = td->td_proc;
@@ -1283,6 +1317,7 @@ ithread_loop(void *arg)
 	    ("%s: ithread and proc linkage out of sync", __func__));
 	ie = ithd->it_event;
 	ie->ie_count = 0;
+	wake = 0;
 
 	/*
 	 * As long as we have interrupts outstanding, go through the
@@ -1323,12 +1358,20 @@ ithread_loop(void *arg)
 		 * set again, so we have to check it again.
 		 */
 		thread_lock(td);
-		if (!ithd->it_need && !(ithd->it_flags & IT_DEAD)) {
+		if (!ithd->it_need && !(ithd->it_flags & (IT_DEAD | IT_WAIT))) {
 			TD_SET_IWAIT(td);
 			ie->ie_count = 0;
 			mi_switch(SW_VOL | SWT_IWAIT, NULL);
 		}
+		if (ithd->it_flags & IT_WAIT) {
+			wake = 1;
+			ithd->it_flags &= ~IT_WAIT;
+		}
 		thread_unlock(td);
+		if (wake) {
+			wakeup(ithd);
+			wake = 0;
+		}
 	}
 }
 
@@ -1439,6 +1482,7 @@ ithread_loop(void *arg)
 	struct thread *td;
 	struct proc *p;
 	int priv;
+	int wake;
 
 	td = curthread;
 	p = td->td_proc;
@@ -1449,6 +1493,7 @@ ithread_loop(void *arg)
 	    ("%s: ithread and proc linkage out of sync", __func__));
 	ie = ithd->it_event;
 	ie->ie_count = 0;
+	wake = 0;
 
 	/*
 	 * As long as we have interrupts outstanding, go through the
@@ -1492,12 +1537,20 @@ ithread_loop(void *arg)
 		 * set again, so we have to check it again.
 		 */
 		thread_lock(td);
-		if (!ithd->it_need && !(ithd->it_flags & IT_DEAD)) {
+		if (!ithd->it_need && !(ithd->it_flags & (IT_DEAD | IT_WAIT))) {
 			TD_SET_IWAIT(td);
 			ie->ie_count = 0;
 			mi_switch(SW_VOL | SWT_IWAIT, NULL);
 		}
+		if (ithd->it_flags & IT_WAIT) {
+			wake = 1;
+			ithd->it_flags &= ~IT_WAIT;
+		}
 		thread_unlock(td);
+		if (wake) {
+			wakeup(ithd);
+			wake = 0;
+		}
 	}
 }
 

Modified: projects/ofed/head/sys/ofed/include/linux/hardirq.h
==============================================================================
--- projects/ofed/head/sys/ofed/include/linux/hardirq.h	Wed Oct 27 21:01:53 2010	(r214434)
+++ projects/ofed/head/sys/ofed/include/linux/hardirq.h	Wed Oct 27 23:18:25 2010	(r214435)
@@ -28,6 +28,12 @@
 #ifndef _LINUX_HARDIRQ_H_
 #define	_LINUX_HARDIRQ_H_
 
-#define	synchronize_irq(irq)	printf("synchronize_irq: Unimplemented\n")
+#include <linux/types.h>
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/interrupt.h>
+
+#define	synchronize_irq(irq)	intr_drain((irq))
 
 #endif	/* _LINUX_HARDIRQ_H_ */

Modified: projects/ofed/head/sys/sys/interrupt.h
==============================================================================
--- projects/ofed/head/sys/sys/interrupt.h	Wed Oct 27 21:01:53 2010	(r214434)
+++ projects/ofed/head/sys/sys/interrupt.h	Wed Oct 27 23:18:25 2010	(r214435)
@@ -177,6 +177,7 @@ int	intr_event_remove_handler(void *cook
 int	intr_getaffinity(int irq, void *mask);
 void	*intr_handler_source(void *cookie);
 int	intr_setaffinity(int irq, void *mask);
+void	intr_drain(int irq);
 int	swi_add(struct intr_event **eventp, const char *name,
 	    driver_intr_t handler, void *arg, int pri, enum intr_type flags,
 	    void **cookiep);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201010272318.o9RNIPAT043359>