Module Name:    src
Committed By:   cherry
Date:           Thu Aug  4 09:07:47 UTC 2011

Modified Files:
        src/sys/arch/xen/include [cherry-xenmp]: evtchn.h hypervisor.h intr.h
        src/sys/arch/xen/x86 [cherry-xenmp]: hypervisor_machdep.c
        src/sys/arch/xen/xen [cherry-xenmp]: evtchn.c xenevt.c

Log Message:
first cut at per-cpu event handling


To generate a diff of this commit:
cvs rdiff -u -r1.18.10.1 -r1.18.10.2 src/sys/arch/xen/include/evtchn.h
cvs rdiff -u -r1.31 -r1.31.10.1 src/sys/arch/xen/include/hypervisor.h
cvs rdiff -u -r1.31.10.2 -r1.31.10.3 src/sys/arch/xen/include/intr.h
cvs rdiff -u -r1.14.2.1 -r1.14.2.2 src/sys/arch/xen/x86/hypervisor_machdep.c
cvs rdiff -u -r1.47.6.1 -r1.47.6.2 src/sys/arch/xen/xen/evtchn.c
cvs rdiff -u -r1.37 -r1.37.2.1 src/sys/arch/xen/xen/xenevt.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/xen/include/evtchn.h
diff -u src/sys/arch/xen/include/evtchn.h:1.18.10.1 src/sys/arch/xen/include/evtchn.h:1.18.10.2
--- src/sys/arch/xen/include/evtchn.h:1.18.10.1	Fri Jun  3 13:27:40 2011
+++ src/sys/arch/xen/include/evtchn.h	Thu Aug  4 09:07:46 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: evtchn.h,v 1.18.10.1 2011/06/03 13:27:40 cherry Exp $	*/
+/*	$NetBSD: evtchn.h,v 1.18.10.2 2011/08/04 09:07:46 cherry Exp $	*/
 
 /*
  *
@@ -42,7 +42,9 @@
 int event_remove_handler(int, int (*func)(void *), void *);
 
 struct intrhand;
-void event_set_iplhandler(struct intrhand *, int);
+void event_set_iplhandler(struct cpu_info *ci,
+			  struct intrhand *, 
+			  int);
 
 extern int debug_port;
 extern int xen_debug_handler(void *);

Index: src/sys/arch/xen/include/hypervisor.h
diff -u src/sys/arch/xen/include/hypervisor.h:1.31 src/sys/arch/xen/include/hypervisor.h:1.31.10.1
--- src/sys/arch/xen/include/hypervisor.h:1.31	Mon Oct 19 18:41:10 2009
+++ src/sys/arch/xen/include/hypervisor.h	Thu Aug  4 09:07:46 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: hypervisor.h,v 1.31 2009/10/19 18:41:10 bouyer Exp $	*/
+/*	$NetBSD: hypervisor.h,v 1.31.10.1 2011/08/04 09:07:46 cherry Exp $	*/
 
 /*
  * Copyright (c) 2006 Manuel Bouyer.
@@ -91,6 +91,7 @@
 #include <xen/xen3-public/io/netif.h>
 #include <xen/xen3-public/io/blkif.h>
 
+#include <machine/cpu.h>
 #include <machine/hypercalls.h>
 
 #undef u8
@@ -136,7 +137,8 @@
 void hypervisor_mask_event(unsigned int);
 void hypervisor_clear_event(unsigned int);
 void hypervisor_enable_ipl(unsigned int);
-void hypervisor_set_ipending(uint32_t, int, int);
+void hypervisor_set_ipending(struct cpu_info *, 
+			     uint32_t, int, int);
 void hypervisor_machdep_attach(void);
 
 /* 

Index: src/sys/arch/xen/include/intr.h
diff -u src/sys/arch/xen/include/intr.h:1.31.10.2 src/sys/arch/xen/include/intr.h:1.31.10.3
--- src/sys/arch/xen/include/intr.h:1.31.10.2	Sun Jun 26 12:56:32 2011
+++ src/sys/arch/xen/include/intr.h	Thu Aug  4 09:07:46 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: intr.h,v 1.31.10.2 2011/06/26 12:56:32 cherry Exp $	*/
+/*	$NetBSD: intr.h,v 1.31.10.3 2011/08/04 09:07:46 cherry Exp $	*/
 /*	NetBSD intr.h,v 1.15 2004/10/31 10:39:34 yamt Exp	*/
 
 /*-
@@ -58,13 +58,8 @@
 	struct intrhand *ev_handlers;	/* handler chain */
 	struct evcnt ev_evcnt;		/* interrupt counter */
 	char ev_evname[32];		/* event counter name */
+	struct cpu_info *ev_cpu;	/* cpu on which this event is bound */
 	struct simplelock ev_lock;	/* protects this structure */
-
-	/* 
-	 * XXX: The lock is quite coursegrained ( for the entire
-	 * handler list ), but contention is expected to be low. See
-	 * how this performs and revisit.
-	 */
 };
 
 /*

Index: src/sys/arch/xen/x86/hypervisor_machdep.c
diff -u src/sys/arch/xen/x86/hypervisor_machdep.c:1.14.2.1 src/sys/arch/xen/x86/hypervisor_machdep.c:1.14.2.2
--- src/sys/arch/xen/x86/hypervisor_machdep.c:1.14.2.1	Fri Jun  3 13:27:41 2011
+++ src/sys/arch/xen/x86/hypervisor_machdep.c	Thu Aug  4 09:07:47 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: hypervisor_machdep.c,v 1.14.2.1 2011/06/03 13:27:41 cherry Exp $	*/
+/*	$NetBSD: hypervisor_machdep.c,v 1.14.2.2 2011/08/04 09:07:47 cherry Exp $	*/
 
 /*
  *
@@ -54,7 +54,7 @@
 
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: hypervisor_machdep.c,v 1.14.2.1 2011/06/03 13:27:41 cherry Exp $");
+__KERNEL_RCSID(0, "$NetBSD: hypervisor_machdep.c,v 1.14.2.2 2011/08/04 09:07:47 cherry Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -86,13 +86,101 @@
 // #define PORT_DEBUG 4
 // #define EARLY_DEBUG_EVENT
 
+static inline unsigned int
+evt_bitstr_to_port(unsigned long l1, unsigned long l2)
+{
+	unsigned int l1i, l2i, port;
+
+	l1i = xen_ffs(l1) - 1;
+	l2i = xen_ffs(l2) - 1;
+
+	port = (l1i << LONG_SHIFT) + l2i;
+	return port;
+}
+
+/* callback function type */
+typedef void (*iterate_func_t)(struct cpu_info *,
+			       unsigned int,
+			       unsigned int,
+			       unsigned int,
+			       void *);
+
+
+static inline void
+evt_iterate_pending(struct cpu_info *ci,
+		    volatile unsigned long *pendingl1,
+		    volatile unsigned long *pendingl2,
+		    volatile unsigned long *mask,
+		    iterate_func_t iterate_pending,
+		    void *iterate_args)
+{
+
+	KASSERT(pendingl1 != NULL);
+	KASSERT(pendingl2 != NULL);
+	
+	unsigned long l1, l2;
+	unsigned int l1i, l2i, port;
+
+	l1 = xen_atomic_xchg(pendingl1, 0);
+	while ((l1i = xen_ffs(l1)) != 0) {
+		l1i--;
+		l1 &= ~(1UL << l1i);
+
+		l2 = pendingl2[l1i] & (mask != NULL ? ~mask[l1i] : -1UL);
+
+		if (mask != NULL) xen_atomic_setbits_l(&mask[l1i], l2);
+		xen_atomic_clearbits_l(&pendingl2[l1i], l2);
+
+		while ((l2i = xen_ffs(l2)) != 0) {
+			l2i--;
+			l2 &= ~(1UL << l2i);
+
+			port = (l1i << LONG_SHIFT) + l2i;
+
+			iterate_pending(ci, port, l1i, l2i, iterate_args);
+		}
+	}
+}
+
+/*
+ * Set per-cpu "pending" information for outstanding events that
+ * cannot be processed now.
+ */
+   
+static inline void
+evt_set_pending(struct cpu_info *ci,
+		unsigned int port,
+		unsigned int l1i,
+		unsigned int l2i,
+		void *args)
+{
+
+	KASSERT(args != NULL);
+	KASSERT(ci != NULL);
+
+	int *ret = args;
+
+	if (evtsource[port]) {
+		hypervisor_set_ipending(ci,
+			evtsource[port]->ev_imask,
+			l1i, l2i);
+		evtsource[port]->ev_evcnt.ev_count++;
+		if (*ret == 0 && ci->ci_ilevel <
+		    evtsource[port]->ev_maxlevel)
+			*ret = 1;
+	}
+#ifdef DOM0OPS
+	else  {
+		/* set pending event */
+		xenevt_setipending(l1i, l2i);
+	}
+#endif
+}
+
 int stipending(void);
 int
 stipending(void)
 {
-	unsigned long l1;
-	unsigned long l2;
-	unsigned int l1i, l2i, port;
 	volatile shared_info_t *s = HYPERVISOR_shared_info;
 	struct cpu_info *ci;
 	volatile struct vcpu_info *vci;
@@ -120,45 +208,19 @@
 	 * we're only called after STIC, so we know that we'll have to
 	 * STI at the end
 	 */
+
 	while (vci->evtchn_upcall_pending) {
 		cli();
+
 		vci->evtchn_upcall_pending = 0;
-		/* NB. No need for a barrier here -- XCHG is a barrier
-		 * on x86. */
-		l1 = xen_atomic_xchg(&vci->evtchn_pending_sel, 0);
-		while ((l1i = xen_ffs(l1)) != 0) {
-			l1i--;
-			l1 &= ~(1UL << l1i);
-
-			l2 = s->evtchn_pending[l1i] & ~s->evtchn_mask[l1i];
-			/*
-			 * mask and clear event. More efficient than calling
-			 * hypervisor_mask/clear_event for each event.
-			 */
-			xen_atomic_setbits_l(&s->evtchn_mask[l1i], l2);
-			xen_atomic_clearbits_l(&s->evtchn_pending[l1i], l2);
-			while ((l2i = xen_ffs(l2)) != 0) {
-				l2i--;
-				l2 &= ~(1UL << l2i);
-
-				port = (l1i << LONG_SHIFT) + l2i;
-				if (evtsource[port]) {
-					hypervisor_set_ipending(
-					    evtsource[port]->ev_imask,
-					    l1i, l2i);
-					evtsource[port]->ev_evcnt.ev_count++;
-					if (ret == 0 && ci->ci_ilevel <
-					    evtsource[port]->ev_maxlevel)
-						ret = 1;
-				}
-#ifdef DOM0OPS
-				else  {
-					/* set pending event */
-					xenevt_setipending(l1i, l2i);
-				}
-#endif
-			}
-		}
+
+		evt_iterate_pending(ci,
+				    &vci->evtchn_pending_sel,
+				    s->evtchn_pending,
+				    s->evtchn_mask,
+				    evt_set_pending,
+				    &ret);
+
 		sti();
 	}
 
@@ -173,12 +235,45 @@
 	return (ret);
 }
 
+/* Iterate through pending events and call the event handler */
+
+static inline void
+evt_do_hypervisor_callback(struct cpu_info *ci,
+			   unsigned int port,
+			   unsigned int l1i,
+			   unsigned int l2i,
+			   void *args)
+{
+	KASSERT(args != NULL);
+	KASSERT(ci == curcpu());
+
+	struct intrframe *regs = args;
+
+#ifdef PORT_DEBUG
+	if (port == PORT_DEBUG)
+		printf("do_hypervisor_callback event %d\n", port);
+#endif
+	if (evtsource[port])
+		call_evtchn_do_event(port, regs);
+#ifdef DOM0OPS
+	else  {
+		if (ci->ci_ilevel < IPL_HIGH) {
+			/* fast path */
+			int oipl = ci->ci_ilevel;
+			ci->ci_ilevel = IPL_HIGH;
+			call_xenevt_event(port);
+			ci->ci_ilevel = oipl;
+		} else {
+			/* set pending event */
+			xenevt_setipending(l1i, l2i);
+		}
+	}
+#endif
+}
+
 void
 do_hypervisor_callback(struct intrframe *regs)
 {
-	unsigned long l1;
-	unsigned long l2;
-	unsigned int l1i, l2i, port;
 	volatile shared_info_t *s = HYPERVISOR_shared_info;
 	struct cpu_info *ci;
 	volatile struct vcpu_info *vci;
@@ -199,51 +294,13 @@
 
 	while (vci->evtchn_upcall_pending) {
 		vci->evtchn_upcall_pending = 0;
-		/* NB. No need for a barrier here -- XCHG is a barrier
-		 * on x86. */
-		l1 = xen_atomic_xchg(&vci->evtchn_pending_sel, 0);
-		while ((l1i = xen_ffs(l1)) != 0) {
-			l1i--;
-			l1 &= ~(1UL << l1i);
-
-			l2 = s->evtchn_pending[l1i] & ~s->evtchn_mask[l1i];
-			/*
-			 * mask and clear the pending events.
-			 * Doing it here for all event that will be processed
-			 * avoids a race with stipending (which can be called
-			 * though evtchn_do_event->splx) that could cause an
-			 * event to be both processed and marked pending.
-			 */
-			xen_atomic_setbits_l(&s->evtchn_mask[l1i], l2);
-			xen_atomic_clearbits_l(&s->evtchn_pending[l1i], l2);
-
-			while ((l2i = xen_ffs(l2)) != 0) {
-				l2i--;
-				l2 &= ~(1UL << l2i);
 
-				port = (l1i << LONG_SHIFT) + l2i;
-#ifdef PORT_DEBUG
-				if (port == PORT_DEBUG)
-					printf("do_hypervisor_callback event %d\n", port);
-#endif
-				if (evtsource[port])
-					call_evtchn_do_event(port, regs);
-#ifdef DOM0OPS
-				else  {
-					if (ci->ci_ilevel < IPL_HIGH) {
-						/* fast path */
-						int oipl = ci->ci_ilevel;
-						ci->ci_ilevel = IPL_HIGH;
-						call_xenevt_event(port);
-						ci->ci_ilevel = oipl;
-					} else {
-						/* set pending event */
-						xenevt_setipending(l1i, l2i);
-					}
-				}
-#endif
-			}
-		}
+		evt_iterate_pending(ci,
+				    &vci->evtchn_pending_sel,
+				    s->evtchn_pending,
+				    s->evtchn_mask,
+				    evt_do_hypervisor_callback,
+				    regs);
 	}
 
 #ifdef DIAGNOSTIC
@@ -303,11 +360,21 @@
 	xen_atomic_clear_bit(&s->evtchn_pending[0], ev);
 }
 
+static inline void
+evt_enable_event(struct cpu_info *ci,
+	       unsigned int port,
+	       unsigned int l1i,
+	       unsigned int l2i,
+	       void *args)
+{
+	KASSERT(ci != NULL);
+	KASSERT(args == NULL);
+	hypervisor_enable_event(port);
+}
+
 void
 hypervisor_enable_ipl(unsigned int ipl)
 {
-	u_long l1, l2;
-	int l1i, l2i;
 	struct cpu_info *ci = curcpu();
 
 	/*
@@ -316,30 +383,21 @@
 	 * we know that all callback for this event have been processed.
 	 */
 
-	l1 = ci->ci_isources[ipl]->ipl_evt_mask1;
-	ci->ci_isources[ipl]->ipl_evt_mask1 = 0;
-	while ((l1i = xen_ffs(l1)) != 0) {
-		l1i--;
-		l1 &= ~(1UL << l1i);
-		l2 = ci->ci_isources[ipl]->ipl_evt_mask2[l1i];
-		ci->ci_isources[ipl]->ipl_evt_mask2[l1i] = 0;
-		while ((l2i = xen_ffs(l2)) != 0) {
-			int evtch;
+	evt_iterate_pending(ci,
+			    &ci->ci_isources[ipl]->ipl_evt_mask1,
+			    ci->ci_isources[ipl]->ipl_evt_mask2,
+			    NULL,
+			    evt_enable_event,
+			    NULL);
 
-			l2i--;
-			l2 &= ~(1UL << l2i);
-
-			evtch = (l1i << LONG_SHIFT) + l2i;
-			hypervisor_enable_event(evtch);
-		}
-	}
 }
 
 void
-hypervisor_set_ipending(uint32_t iplmask, int l1, int l2)
+hypervisor_set_ipending(struct cpu_info *ci,
+			uint32_t iplmask, 
+			int l1, int l2)
 {
 	int ipl;
-	struct cpu_info *ci = curcpu();
 
 	/* set pending bit for the appropriate IPLs */	
 	ci->ci_ipending |= iplmask;

Index: src/sys/arch/xen/xen/evtchn.c
diff -u src/sys/arch/xen/xen/evtchn.c:1.47.6.1 src/sys/arch/xen/xen/evtchn.c:1.47.6.2
--- src/sys/arch/xen/xen/evtchn.c:1.47.6.1	Fri Jun  3 13:27:42 2011
+++ src/sys/arch/xen/xen/evtchn.c	Thu Aug  4 09:07:47 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: evtchn.c,v 1.47.6.1 2011/06/03 13:27:42 cherry Exp $	*/
+/*	$NetBSD: evtchn.c,v 1.47.6.2 2011/08/04 09:07:47 cherry Exp $	*/
 
 /*
  * Copyright (c) 2006 Manuel Bouyer.
@@ -54,7 +54,7 @@
 
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: evtchn.c,v 1.47.6.1 2011/06/03 13:27:42 cherry Exp $");
+__KERNEL_RCSID(0, "$NetBSD: evtchn.c,v 1.47.6.2 2011/08/04 09:07:47 cherry Exp $");
 
 #include "opt_xen.h"
 #include "isa.h"
@@ -234,14 +234,17 @@
 	ci->ci_data.cpu_nintr++;
 	evtsource[evtch]->ev_evcnt.ev_count++;
 	ilevel = ci->ci_ilevel;
-	if (evtsource[evtch]->ev_maxlevel <= ilevel) {
+	if (evtsource[evtch]->ev_maxlevel <= ilevel ||
+	    evtsource[evtch]->ev_cpu != ci /* XXX: get stats */) {
 #ifdef IRQ_DEBUG
 		if (evtch == IRQ_DEBUG)
 		    printf("evtsource[%d]->ev_maxlevel %d <= ilevel %d\n",
 		    evtch, evtsource[evtch]->ev_maxlevel, ilevel);
 #endif
-		hypervisor_set_ipending(evtsource[evtch]->ev_imask,
-		    evtch >> LONG_SHIFT, evtch & LONG_MASK);
+		hypervisor_set_ipending(evtsource[evtch]->ev_cpu,
+					evtsource[evtch]->ev_imask,
+					evtch >> LONG_SHIFT,
+					evtch & LONG_MASK);
 		/* leave masked */
 		return 0;
 	}
@@ -251,13 +254,14 @@
 	simple_lock(&evtsource[evtch]->ev_lock);
 	ih = evtsource[evtch]->ev_handlers;
 	while (ih != NULL) {
-		if (ih->ih_level <= ilevel) {
+		if (ih->ih_level <= ilevel ||
+		   ih->ih_cpu != ci) {
 #ifdef IRQ_DEBUG
 		if (evtch == IRQ_DEBUG)
 		    printf("ih->ih_level %d <= ilevel %d\n", ih->ih_level, ilevel);
 #endif
 			cli();
-			hypervisor_set_ipending(iplmask,
+			hypervisor_set_ipending(ih->ih_cpu, iplmask,
 			    evtch >> LONG_SHIFT, evtch & LONG_MASK);
 			/* leave masked */
 			simple_unlock(&evtsource[evtch]->ev_lock);
@@ -287,6 +291,7 @@
 				ci->ci_ilevel = i;
 				for (ih = ci->ci_isources[i]->ipl_handlers;
 				    ih != NULL; ih = ih->ih_ipl_next) {
+					KASSERT(ih->ih_cpu == ci);
 					sti();
 					ih_fun = (void *)ih->ih_fun;
 					ih_fun(ih->ih_arg, regs);
@@ -582,6 +587,7 @@
 	ih->ih_arg = ih->ih_realarg = arg;
 	ih->ih_evt_next = NULL;
 	ih->ih_ipl_next = NULL;
+	ih->ih_cpu = ci;
 #ifdef MULTIPROCESSOR
 	if (!mpsafe) {
 		ih->ih_fun = intr_biglock_wrapper;
@@ -591,8 +597,8 @@
 
 	s = splhigh();
 
-	/* register handler for spllower() */
-	event_set_iplhandler(ih, level);
+	/* register per-cpu handler for spllower() */
+	event_set_iplhandler(ci, ih, level);
 
 	/* register handler for event channel */
 	if (evtsource[evtch] == NULL) {
@@ -602,6 +608,13 @@
 			panic("can't allocate fixed interrupt source");
 
 		evts->ev_handlers = ih;
+		/* 
+		 * XXX: We're assuming here that ci is the same cpu as
+		 * the one on which this event/port is bound on. The
+		 * api needs to be reshuffled so that this assumption
+		 * is more explicitly implemented.
+		 */
+		evts->ev_cpu = ci; 
 		simple_lock_init(&evts->ev_lock);
 		evtsource[evtch] = evts;
 		if (evname)
@@ -638,11 +651,13 @@
 }
 
 void
-event_set_iplhandler(struct intrhand *ih, int level)
+event_set_iplhandler(struct cpu_info *ci,
+		     struct intrhand *ih,
+		     int level)
 {
-	struct cpu_info *ci = curcpu();
 	struct iplsource *ipls;
 
+	KASSERT(ci == ih->ih_cpu);
 	if (ci->ci_isources[level] == NULL) {
 		ipls = malloc(sizeof (struct iplsource),
 		    M_DEVBUF, M_WAITOK|M_ZERO);

Index: src/sys/arch/xen/xen/xenevt.c
diff -u src/sys/arch/xen/xen/xenevt.c:1.37 src/sys/arch/xen/xen/xenevt.c:1.37.2.1
--- src/sys/arch/xen/xen/xenevt.c:1.37	Sun May 22 04:27:15 2011
+++ src/sys/arch/xen/xen/xenevt.c	Thu Aug  4 09:07:47 2011
@@ -1,4 +1,4 @@
-/*      $NetBSD: xenevt.c,v 1.37 2011/05/22 04:27:15 rmind Exp $      */
+/*      $NetBSD: xenevt.c,v 1.37.2.1 2011/08/04 09:07:47 cherry Exp $      */
 
 /*
  * Copyright (c) 2005 Manuel Bouyer.
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: xenevt.c,v 1.37 2011/05/22 04:27:15 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xenevt.c,v 1.37.2.1 2011/08/04 09:07:47 cherry Exp $");
 
 #include "opt_xen.h"
 #include <sys/param.h>
@@ -160,6 +160,7 @@
 	ih->ih_fun = ih->ih_realfun = xenevt_processevt;
 	ih->ih_arg = ih->ih_realarg = NULL;
 	ih->ih_ipl_next = NULL;
+	ih->ih_cpu = curcpu();
 #ifdef MULTIPROCESSOR
 	if (!mpsafe) {
 		ih->ih_fun = intr_biglock_wrapper;
@@ -168,7 +169,7 @@
 #endif /* MULTIPROCESSOR */
 
 	s = splhigh();
-	event_set_iplhandler(ih, level);
+	event_set_iplhandler(ih->ih_cpu, ih, level);
 	splx(s);
 }
 
@@ -178,7 +179,7 @@
 {
 	xenevt_ev1 |= 1UL << l1;
 	xenevt_ev2[l1] |= 1UL << l2;
-	curcpu()->ci_ipending |= 1 << IPL_HIGH;
+	curcpu()/*XXX*/->ci_ipending |= 1 << IPL_HIGH;
 }
 
 /* process pending events */

Reply via email to