Module Name: src Committed By: cherry Date: Fri Dec 28 06:29:56 UTC 2012
Modified Files: src/sys/arch/xen/include: evtchn.h hypervisor.h src/sys/arch/xen/x86: hypervisor_machdep.c src/sys/arch/xen/xen: evtchn.c Log Message: Simplify the xen event handler callback by: - moving the interrupt handler callback traversal into a separate function. - using evt_iterate_bits() to scan through the pending bitfield - removing cross-cpu pending actions - events recieved on the wrong vcpu are re-routed via hypervisor_send_event(). - simplifying nested while() loops by encapsulating them in equivalent functions. Many thanks for multiple reviews by bouyer@ and jym@ To generate a diff of this commit: cvs rdiff -u -r1.20 -r1.21 src/sys/arch/xen/include/evtchn.h cvs rdiff -u -r1.39 -r1.40 src/sys/arch/xen/include/hypervisor.h cvs rdiff -u -r1.23 -r1.24 src/sys/arch/xen/x86/hypervisor_machdep.c cvs rdiff -u -r1.65 -r1.66 src/sys/arch/xen/xen/evtchn.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.20 src/sys/arch/xen/include/evtchn.h:1.21 --- src/sys/arch/xen/include/evtchn.h:1.20 Tue Sep 20 00:12:23 2011 +++ src/sys/arch/xen/include/evtchn.h Fri Dec 28 06:29:56 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: evtchn.h,v 1.20 2011/09/20 00:12:23 jym Exp $ */ +/* $NetBSD: evtchn.h,v 1.21 2012/12/28 06:29:56 cherry Exp $ */ /* * @@ -33,6 +33,9 @@ extern struct evtsource *evtsource[]; +#include <sys/mutex.h> +extern kmutex_t evtlock[]; + void events_default_setup(void); void events_init(void); bool events_suspend(void); Index: src/sys/arch/xen/include/hypervisor.h diff -u src/sys/arch/xen/include/hypervisor.h:1.39 src/sys/arch/xen/include/hypervisor.h:1.40 --- src/sys/arch/xen/include/hypervisor.h:1.39 Sun Nov 25 08:39:35 2012 +++ src/sys/arch/xen/include/hypervisor.h Fri Dec 28 06:29:56 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: hypervisor.h,v 1.39 2012/11/25 08:39:35 cherry Exp $ */ +/* $NetBSD: hypervisor.h,v 1.40 2012/12/28 06:29:56 cherry Exp $ */ /* * Copyright (c) 2006 Manuel Bouyer. @@ -142,6 +142,7 @@ void hypervisor_unmask_event(unsigned in void hypervisor_mask_event(unsigned int); void hypervisor_clear_event(unsigned int); void hypervisor_enable_ipl(unsigned int); +void hypervisor_do_iplpending(unsigned int, void *); void hypervisor_set_ipending(uint32_t, int, int); void hypervisor_machdep_attach(void); void hypervisor_machdep_resume(void); Index: src/sys/arch/xen/x86/hypervisor_machdep.c diff -u src/sys/arch/xen/x86/hypervisor_machdep.c:1.23 src/sys/arch/xen/x86/hypervisor_machdep.c:1.24 --- src/sys/arch/xen/x86/hypervisor_machdep.c:1.23 Sun Nov 25 08:39:36 2012 +++ src/sys/arch/xen/x86/hypervisor_machdep.c Fri Dec 28 06:29:56 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: hypervisor_machdep.c,v 1.23 2012/11/25 08:39:36 cherry Exp $ */ +/* $NetBSD: hypervisor_machdep.c,v 1.24 2012/12/28 06:29:56 cherry Exp $ */ /* * @@ -54,7 +54,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: hypervisor_machdep.c,v 1.23 2012/11/25 08:39:36 cherry Exp $"); +__KERNEL_RCSID(0, "$NetBSD: hypervisor_machdep.c,v 1.24 2012/12/28 06:29:56 cherry Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -187,7 +187,7 @@ stipending(void) */ while (vci->evtchn_upcall_pending) { - cli(); + x86_disable_intr(); vci->evtchn_upcall_pending = 0; @@ -195,7 +195,7 @@ stipending(void) s->evtchn_pending, s->evtchn_mask, evt_set_pending, &ret); - sti(); + x86_enable_intr(); } #if 0 @@ -284,6 +284,82 @@ do_hypervisor_callback(struct intrframe #endif } +/* Iterate through pending events and call the event handler */ +struct splargs { + int ipl; + struct intrframe *regs; +}; + +static inline void +evt_do_iplcallback(unsigned int evtch, unsigned int l1i, + unsigned int l2i, void *args) +{ + KASSERT(args != NULL); + struct splargs *sargs = args; + + struct intrhand *ih; + int (*ih_fun)(void *, void *); + + int ipl = sargs->ipl; + struct cpu_info *ci = curcpu(); + struct intrframe *regs = sargs->regs; + + KASSERT(evtsource[evtch] != 0); + + KASSERT(ci->ci_ilevel == ipl); + + KASSERT(x86_read_psl() != 0); + x86_enable_intr(); + mutex_spin_enter(&evtlock[evtch]); + ih = evtsource[evtch]->ev_handlers; + while (ih != NULL) { + if (ih->ih_cpu != ci) { /* Skip non-local handlers */ + ih = ih->ih_evt_next; + continue; + } + if (ih->ih_level == ipl) { + KASSERT(x86_read_psl() == 0); + x86_disable_intr(); + ci->ci_ilevel = ih->ih_level; + x86_enable_intr(); + ih_fun = (void *)ih->ih_fun; + ih_fun(ih->ih_arg, regs); + if (ci->ci_ilevel != ipl) { + printf("evtchn_do_event: " + "handler %p didn't lower " + "ipl %d %d\n", + ih_fun, ci->ci_ilevel, ipl); + } + } + ih = ih->ih_evt_next; + } + mutex_spin_exit(&evtlock[evtch]); + hypervisor_enable_event(evtch); + x86_disable_intr(); + + KASSERT(ci->ci_ilevel == ipl); +} + +/* + * Iterate through all pending interrupt handlers at 'ipl', on current + * cpu. + */ +void +hypervisor_do_iplpending(unsigned int ipl, void *regs) +{ + struct cpu_info *ci; + struct splargs splargs = { + .ipl = ipl, + .regs = regs}; + + ci = curcpu(); + + evt_iterate_bits(&ci->ci_isources[ipl]->ipl_evt_mask1, + ci->ci_isources[ipl]->ipl_evt_mask2, NULL, + evt_do_iplcallback, &splargs); +} + + void hypervisor_send_event(struct cpu_info *ci, unsigned int ev) { @@ -437,13 +513,6 @@ hypervisor_set_ipending(uint32_t iplmask KASSERT(ci->ci_isources[ipl] != NULL); ci->ci_isources[ipl]->ipl_evt_mask1 |= 1UL << l1; ci->ci_isources[ipl]->ipl_evt_mask2[l1] |= 1UL << l2; - if (__predict_false(ci != curcpu())) { - if (xen_send_ipi(ci, XEN_IPI_HVCB)) { - panic("hypervisor_set_ipending: " - "xen_send_ipi(cpu%d, XEN_IPI_HVCB) failed\n", - (int) ci->ci_cpuid); - } - } } void Index: src/sys/arch/xen/xen/evtchn.c diff -u src/sys/arch/xen/xen/evtchn.c:1.65 src/sys/arch/xen/xen/evtchn.c:1.66 --- src/sys/arch/xen/xen/evtchn.c:1.65 Sun Nov 25 20:56:33 2012 +++ src/sys/arch/xen/xen/evtchn.c Fri Dec 28 06:29:56 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: evtchn.c,v 1.65 2012/11/25 20:56:33 cherry Exp $ */ +/* $NetBSD: evtchn.c,v 1.66 2012/12/28 06:29:56 cherry Exp $ */ /* * Copyright (c) 2006 Manuel Bouyer. @@ -54,7 +54,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: evtchn.c,v 1.65 2012/11/25 20:56:33 cherry Exp $"); +__KERNEL_RCSID(0, "$NetBSD: evtchn.c,v 1.66 2012/12/28 06:29:56 cherry Exp $"); #include "opt_xen.h" #include "isa.h" @@ -89,7 +89,7 @@ static kmutex_t evtchn_lock; struct evtsource *evtsource[NR_EVENT_CHANNELS]; /* channel locks */ -static kmutex_t evtlock[NR_EVENT_CHANNELS]; +kmutex_t evtlock[NR_EVENT_CHANNELS]; /* Reference counts for bindings to event channels XXX: redo for SMP */ static uint8_t evtch_bindcount[NR_EVENT_CHANNELS]; @@ -228,6 +228,50 @@ events_resume (void) } +static int +xspllower(int ilevel, void *regs) +{ + int i; + uint32_t iplbit; + uint32_t iplpending; + + struct cpu_info *ci; + + KASSERT(kpreempt_disabled()); + KASSERT(x86_read_psl() != 0); /* Interrupts must be disabled */ + + ci = curcpu(); + ci->ci_idepth++; + + KASSERT(ilevel < ci->ci_ilevel); + /* + * C version of spllower(). ASTs will be checked when + * hypevisor_callback() exits, so no need to check here. + */ + iplpending = (IUNMASK(ci, ilevel) & ci->ci_ipending); + while (iplpending != 0) { + iplbit = 1 << (NIPL - 1); + i = (NIPL - 1); + while (iplpending != 0 && i > ilevel) { + while (iplpending & iplbit) { + ci->ci_ipending &= ~iplbit; + ci->ci_ilevel = i; + hypervisor_do_iplpending(i, regs); + KASSERT(x86_read_psl() != 0); + /* more pending IPLs may have been registered */ + iplpending = + (IUNMASK(ci, ilevel) & ci->ci_ipending); + } + i--; + iplbit >>= 1; + } + } + KASSERT(x86_read_psl() != 0); + ci->ci_ilevel = ilevel; + ci->ci_idepth--; + return 0; +} + unsigned int evtchn_do_event(int evtch, struct intrframe *regs) { @@ -236,8 +280,6 @@ evtchn_do_event(int evtch, struct intrfr struct intrhand *ih; int (*ih_fun)(void *, void *); uint32_t iplmask; - int i; - uint32_t iplbit; #ifdef DIAGNOSTIC if (evtch >= NR_EVENT_CHANNELS) { @@ -292,9 +334,12 @@ evtchn_do_event(int evtch, struct intrfr } ci->ci_ilevel = evtsource[evtch]->ev_maxlevel; iplmask = evtsource[evtch]->ev_imask; - sti(); + + KASSERT(x86_read_psl() != 0); + x86_enable_intr(); mutex_spin_enter(&evtlock[evtch]); ih = evtsource[evtch]->ev_handlers; + while (ih != NULL) { if (ih->ih_cpu != ci) { hypervisor_send_event(ih->ih_cpu, evtch); @@ -307,60 +352,44 @@ evtchn_do_event(int evtch, struct intrfr if (evtch == IRQ_DEBUG) printf("ih->ih_level %d <= ilevel %d\n", ih->ih_level, ilevel); #endif - cli(); - hypervisor_set_ipending(iplmask, - evtch >> LONG_SHIFT, evtch & LONG_MASK); - /* leave masked */ mutex_spin_exit(&evtlock[evtch]); + x86_disable_intr(); + hypervisor_set_ipending(iplmask, + evtch >> LONG_SHIFT, evtch & LONG_MASK); + + /* leave masked */ goto splx; } iplmask &= ~IUNMASK(ci, ih->ih_level); - ci->ci_ilevel = ih->ih_level; + + KASSERT(x86_read_psl() == 0); + KASSERT(ih->ih_level > ilevel); + + { /* Lower current spl to current handler */ + x86_disable_intr(); + + /* assert for handlers being sorted by spl */ + KASSERT(ci->ci_ilevel >= ih->ih_level); + + /* Lower it */ + ci->ci_ilevel = ih->ih_level; + + x86_enable_intr(); + } + + /* Assert handler doesn't break spl rules */ + KASSERT(ih->ih_level > ilevel); + ih_fun = (void *)ih->ih_fun; ih_fun(ih->ih_arg, regs); ih = ih->ih_evt_next; } mutex_spin_exit(&evtlock[evtch]); - cli(); + x86_disable_intr(); hypervisor_enable_event(evtch); splx: - /* - * C version of spllower(). ASTs will be checked when - * hypevisor_callback() exits, so no need to check here. - */ - iplmask = (IUNMASK(ci, ilevel) & ci->ci_ipending); - while (iplmask != 0) { - iplbit = 1 << (NIPL - 1); - i = (NIPL - 1); - while (iplmask != 0 && i > ilevel) { - while (iplmask & iplbit) { - ci->ci_ipending &= ~iplbit; - 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); - cli(); - if (ci->ci_ilevel != i) { - printf("evtchn_do_event: " - "handler %p didn't lower " - "ipl %d %d\n", - ih_fun, ci->ci_ilevel, i); - ci->ci_ilevel = i; - } - } - hypervisor_enable_ipl(i); - /* more pending IPLs may have been registered */ - iplmask = - (IUNMASK(ci, ilevel) & ci->ci_ipending); - } - i--; - iplbit >>= 1; - } - } - ci->ci_ilevel = ilevel; + KASSERT(ci->ci_ilevel > ilevel); + xspllower(ilevel, regs); return 0; }