Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 30 Nov 2006 09:07:48 -0800
From:      Marcel Moolenaar <xcllnt@mac.com>
To:        ppc@FreeBSD.org
Subject:   Please review: shared interrupts with fast handlers
Message-ID:  <E20D6528-5B1B-4F22-A36F-55ED676DA9F4@mac.com>

next in thread | raw e-mail | index | archive | help

--Apple-Mail-7--231809268
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
	charset=US-ASCII;
	format=flowed

All,

Attached a patch to support interrupt sharing with fast handlers. It's
pretty much copied from ia64. Please review.

With these changes, vmstat -i shows:

imac% vmstat -i
interrupt                          total       rate
irq19:                            102984          2
irq27:                                 3          0
irq28:                                 1          0
irq40:                                 1          0
irq41:                             25400          0
Total                             128389          2

I think this is the same as before, but can't really test right now.
It's not that informative though. It's probably nicer to see the
actual device name, as in:

imac% vmstat -i
interrupt                          total       rate
irq19:                            102984          2
ohci0:                                 3          0
ohci1:                                 1          0
fwohci0:                               1          0
gem0:                              25400          0
Total                             128389          2

Did I changethe output of vmstat -i?
If not, should I do that?

Thanks,


--Apple-Mail-7--231809268
Content-Transfer-Encoding: 7bit
Content-Type: application/octet-stream; x-unix-mode=0644;
	name=intr_machdep.diff
Content-Disposition: attachment;
	filename=intr_machdep.diff

Index: intr_machdep.c
===================================================================
RCS file: /home/ncvs/src/sys/powerpc/powerpc/intr_machdep.c,v
retrieving revision 1.8
diff -u -r1.8 intr_machdep.c
--- intr_machdep.c	2 Aug 2006 17:50:31 -0000	1.8
+++ intr_machdep.c	30 Nov 2006 04:48:40 -0000
@@ -66,6 +66,7 @@
 #include <sys/queue.h>
 #include <sys/bus.h>
 #include <sys/interrupt.h>
+#include <sys/ktr.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/mutex.h>
@@ -82,25 +83,18 @@
 
 MALLOC_DEFINE(M_INTR, "intr", "interrupt handler data");
 
-static int	intr_initialized = 0;
+struct ppc_intr {
+	struct intr_event *event;
+	long *cntp;
+};
+
+static struct mtx ppc_intrs_lock;
+static struct ppc_intr **ppc_intrs;
+static u_int ppc_nintrs;
 
-static u_int		intr_nirq;
-static struct		ppc_intr_handler *intr_handlers;
+static int intrcnt_index;
 
-static struct		mtx intr_table_lock;
-
-extern int	extint, extsize;
-extern u_long	extint_call;
-
-static int 		intrcnt_index;
-static ih_func_t	intr_stray_handler;
-static ih_func_t	sched_ithd;
-
-static void		(*irq_enable)(uintptr_t);
-static void		(*irq_disable)(uintptr_t);
-
-static void intrcnt_setname(const char *name, int index);
-static void intrcnt_updatename(struct ppc_intr_handler *ih);
+static void (*irq_enable)(uintptr_t);
 
 static void
 intrcnt_setname(const char *name, int index)
@@ -109,85 +103,33 @@
 	    MAXCOMLEN, name);
 }
 
-static void
-intrcnt_updatename(struct ppc_intr_handler *ih)
-{
-	intrcnt_setname(ih->ih_event->ie_fullname, ih->ih_index);
-}
-
-static void
-intrcnt_register(struct ppc_intr_handler *ih)
-{
-	char straystr[MAXCOMLEN + 1];
-
-	KASSERT(ih->ih_event != NULL,
-		("%s: ppc_intr_handler with no event", __func__));
-
-	ih->ih_index = intrcnt_index;
-	intrcnt_index += 2;
-	snprintf(straystr, MAXCOMLEN + 1, "stray irq%d", ih->ih_irq);
-	intrcnt_updatename(ih);
-	ih->ih_count = &intrcnt[ih->ih_index];
-	intrcnt_setname(straystr, ih->ih_index + 1);
-	ih->ih_straycount = &intrcnt[ih->ih_index + 1];
-}
-
 void
 intr_init(void (*handler)(void), int nirq, void (*irq_e)(uintptr_t),
     void (*irq_d)(uintptr_t))
 {
-	int		i;
-	u_int32_t	msr;
-
-	if (intr_initialized != 0)
-		panic("intr_init: interrupts intialized twice\n");
+	static int initialized = 0;
+	uint32_t msr;
 
-	intr_initialized++;
+	if (initialized)
+		panic("intr_init: interrupts initialized twice\n");
+	initialized++;
 
-	intr_nirq = nirq;
-	intr_handlers = malloc(nirq * sizeof(struct ppc_intr_handler), M_INTR,
+	ppc_nintrs = nirq;
+	ppc_intrs = malloc(nirq * sizeof(struct ppc_intr *), M_INTR,
 	    M_NOWAIT|M_ZERO);
-	if (intr_handlers == NULL)
+	if (ppc_intrs == NULL)
 		panic("intr_init: unable to allocate interrupt handler array");
 
-	for (i = 0; i < nirq; i++) {
-		intr_handlers[i].ih_func = intr_stray_handler;
-		intr_handlers[i].ih_arg = &intr_handlers[i];
-		intr_handlers[i].ih_irq = i;
-		intr_handlers[i].ih_flags = 0;
-		/* mux all initial stray irqs onto same count... */
-		intr_handlers[i].ih_straycount = &intrcnt[0];
-	}
+	mtx_init(&ppc_intrs_lock, "intr table", NULL, MTX_SPIN);
+
+	irq_enable = irq_e;
 
 	intrcnt_setname("???", 0);
 	intrcnt_index = 1;
 
 	msr = mfmsr();
 	mtmsr(msr & ~PSL_EE);
-
 	ext_intr_install(handler);
-
-	mtmsr(msr);
-
-	irq_enable = irq_e;
-	irq_disable = irq_d;
-
-	mtx_init(&intr_table_lock, "intr table", NULL, MTX_SPIN);
-}
-
-void
-intr_setup(u_int irq, ih_func_t *ihf, void *iha, u_int flags)
-{
-	u_int32_t	msr;
-
-	msr = mfmsr();
-	mtmsr(msr & ~PSL_EE);
-
-	intr_handlers[irq].ih_func = ihf;
-	intr_handlers[irq].ih_arg = iha;
-	intr_handlers[irq].ih_irq = irq;
-	intr_handlers[irq].ih_flags = flags;
-
 	mtmsr(msr);
 }
 
@@ -195,122 +137,111 @@
 inthand_add(const char *name, u_int irq, void (*handler)(void *), void *arg,
     int flags, void **cookiep)
 {
-	struct	ppc_intr_handler *ih;
-	struct	intr_event *event, *orphan;
-	int	error = 0;
-	int	created_event = 0;
+	struct ppc_intr *i, *orphan;
+	u_int idx;
+	int error;
 
 	/*
 	 * Work around a race where more than one CPU may be registering
 	 * handlers on the same IRQ at the same time.
 	 */
-	ih = &intr_handlers[irq];
-	mtx_lock_spin(&intr_table_lock);
-	event = ih->ih_event;
-	mtx_unlock_spin(&intr_table_lock);
-	if (event == NULL) {
-		error = intr_event_create(&event, (void *)irq, 0,
+	mtx_lock_spin(&ppc_intrs_lock);
+	i = ppc_intrs[irq];
+	mtx_unlock_spin(&ppc_intrs_lock);
+
+	if (i == NULL) {
+		i = malloc(sizeof(*i), M_INTR, M_NOWAIT);
+		if (i == NULL)
+			return (ENOMEM);
+		error = intr_event_create(&i->event, (void *)irq, 0,
 		    (void (*)(void *))irq_enable, "irq%d:", irq);
-		if (error)
+		if (error) {
+			free(i, M_INTR);
 			return (error);
+		}
 
-		mtx_lock_spin(&intr_table_lock);
+		mtx_lock_spin(&ppc_intrs_lock);
+		if (ppc_intrs[irq] != NULL) {
+			orphan = i;
+			i = ppc_intrs[irq];
+			mtx_unlock_spin(&ppc_intrs_lock);
 
-		if (ih->ih_event == NULL) {
-			ih->ih_event = event;
-			created_event++;
-			mtx_unlock_spin(&intr_table_lock);
+			intr_event_destroy(orphan->event);
+			free(orphan, M_INTR);
 		} else {
-			orphan = event;
-			event = ih->ih_event;
-			mtx_unlock_spin(&intr_table_lock);
-			intr_event_destroy(orphan);
+			ppc_intrs[irq] = i;
+			idx = intrcnt_index++;
+			mtx_unlock_spin(&ppc_intrs_lock);
+
+			i->cntp = &intrcnt[idx];
+			intrcnt_setname(i->event->ie_fullname, idx);
 		}
 	}
 
-	/* XXX: Should probably fix support for multiple FAST. */
-	if (flags & INTR_FAST)
-		flags |= INTR_EXCL;
-	error = intr_event_add_handler(event, name, handler, arg,
+	error = intr_event_add_handler(i->event, name, handler, arg,
 	    intr_priority(flags), flags, cookiep);
-
-	if ((flags & INTR_FAST) == 0 || error)
-		intr_setup(irq, sched_ithd, ih, flags);
-
-	if (error)
-		return (error);
-
-	if (flags & INTR_FAST)
-		intr_setup(irq, handler, arg, flags);
-
-	intrcnt_register(ih);
-
-	return (0);
+	return (error);
 }
 
 int
 inthand_remove(u_int irq, void *cookie)
 {
-	struct	ppc_intr_handler *ih;
-	int	error;
-
-	error = intr_event_remove_handler(cookie);
 
-	if (error == 0) {
-		ih = &intr_handlers[irq];
-
-		mtx_lock_spin(&intr_table_lock);
-
-		if (ih->ih_event == NULL) {
-			intr_setup(irq, intr_stray_handler, ih, 0);
-		} else {
-			intr_setup(irq, sched_ithd, ih, 0);
-		}
-
-		mtx_unlock_spin(&intr_table_lock);
-	}
-
-	return (error);
+	return (intr_event_remove_handler(cookie));
 }
 
 void
 intr_handle(u_int irq)
 {
-	atomic_add_long(intr_handlers[irq].ih_count, 1);
-	intr_handlers[irq].ih_func(intr_handlers[irq].ih_arg);
+	struct ppc_intr *i;
+	struct intr_event *ie;
+	struct intr_handler *ih;
+	int error, sched;
+
+	i = ppc_intrs[irq];
+	if (i == NULL)
+		goto stray;
 
-	/* XXX wrong thing when using pre-emption ? */
-	if ((intr_handlers[irq].ih_flags & INTR_FAST) != 0)
-		irq_enable(irq);
-}
-
-static void
-intr_stray_handler(void *cookie)
-{
-	struct	ppc_intr_handler *ih;
+	atomic_add_long(i->cntp, 1);
 
-	ih = (struct ppc_intr_handler *)cookie;
+	ie = i->event;
+	KASSERT(ie != NULL, ("%s: interrupt without an event", __func__));
 
-	if (*intr_handlers[ih->ih_irq].ih_straycount < MAX_STRAY_LOG) {
-		printf("stray irq %d\n", ih->ih_irq);
+	if (TAILQ_EMPTY(&ie->ie_handlers))
+		goto stray;
 
-		atomic_add_long(intr_handlers[ih->ih_irq].ih_straycount, 1);
-		if (*intr_handlers[ih->ih_irq].ih_straycount >= MAX_STRAY_LOG)
-			printf("got %d stray irq %d's: not logging anymore\n",
-			       MAX_STRAY_LOG, ih->ih_irq);
+	/*
+	 * Execute all fast interrupt handlers directly without Giant.  Note
+	 * that this means that any fast interrupt handler must be MP safe.
+	 */
+	sched = 0;
+	critical_enter();
+	TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) {
+		if (!(ih->ih_flags & IH_FAST)) {
+			sched = 1;
+			continue;
+		}
+		CTR4(KTR_INTR, "%s: exec %p(%p) for %s", __func__,
+		    ih->ih_handler, ih->ih_argument, ih->ih_name);
+		ih->ih_handler(ih->ih_argument);
 	}
-}
-
-static void
-sched_ithd(void *cookie)
-{
-	struct	ppc_intr_handler *ih;
-	int	error;
+	critical_exit();
 
-	ih = (struct ppc_intr_handler *)cookie;
-
-	error = intr_event_schedule_thread(ih->ih_event);
+	if (sched) {
+		error = intr_event_schedule_thread(ie);
+		KASSERT(error == 0, ("%s: impossible stray interrupt",
+		    __func__));
+	} else
+		irq_enable(irq);
+	return;
 
-	if (error == EINVAL)
-		intr_stray_handler(ih);
+stray:
+	atomic_add_long(&intrcnt[0], 1);
+	if (intrcnt[0] <= MAX_STRAY_LOG) {
+		printf("stray irq %d\n", irq);
+		if (intrcnt[0] >= MAX_STRAY_LOG) {
+			printf("got %d stray interrupts, not logging anymore\n",
+			       MAX_STRAY_LOG);
+		}
+	}
 }

--Apple-Mail-7--231809268
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
	charset=US-ASCII;
	format=flowed


-- 
Marcel Moolenaar
xcllnt@mac.com



--Apple-Mail-7--231809268--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?E20D6528-5B1B-4F22-A36F-55ED676DA9F4>