svn commit: r214435 - in projects/ofed/head/sys: kern
ofed/include/linux sys
Jeff Roberson
jeff at FreeBSD.org
Wed Oct 27 23:18:26 UTC 2010
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);
More information about the svn-src-projects
mailing list