From e3e720d87d109840b007747fe63ac372ccf9b95f Mon Sep 17 00:00:00 2001 From: bouyer Date: Tue, 19 Feb 2008 13:25:53 +0000 Subject: [PATCH] Fix xenevt to not call softint_schedule() above IPL_HIGH: Register a ipl callback for IPL_HIGH. if the current ipl level is too high, just record the event in a bitmap, and record IPL_HIGH as pending. The callback will process the pending events. --- sys/arch/xen/include/evtchn.h | 5 +- sys/arch/xen/include/xen.h | 3 +- sys/arch/xen/x86/hypervisor_machdep.c | 24 ++++++-- sys/arch/xen/xen/evtchn.c | 49 +++++++++------ sys/arch/xen/xen/xenevt.c | 87 +++++++++++++++++++++------ 5 files changed, 121 insertions(+), 47 deletions(-) diff --git a/sys/arch/xen/include/evtchn.h b/sys/arch/xen/include/evtchn.h index 11adb6400c0d..dc369e93c7f6 100644 --- a/sys/arch/xen/include/evtchn.h +++ b/sys/arch/xen/include/evtchn.h @@ -1,4 +1,4 @@ -/* $NetBSD: evtchn.h,v 1.14 2007/12/12 22:16:32 bouyer Exp $ */ +/* $NetBSD: evtchn.h,v 1.15 2008/02/19 13:25:53 bouyer Exp $ */ /* * @@ -45,6 +45,9 @@ void call_evtchn_do_event(int, struct intrframe *); int event_set_handler(int, int (*func)(void *), void *, int, const char *); int event_remove_handler(int, int (*func)(void *), void *); +struct intrhand; +void event_set_iplhandler(struct intrhand *, int); + extern int debug_port; extern int xen_debug_handler(void *); diff --git a/sys/arch/xen/include/xen.h b/sys/arch/xen/include/xen.h index 70a06d26830e..330f27ce357f 100644 --- a/sys/arch/xen/include/xen.h +++ b/sys/arch/xen/include/xen.h @@ -1,4 +1,4 @@ -/* $NetBSD: xen.h,v 1.26 2008/01/11 20:00:41 bouyer Exp $ */ +/* $NetBSD: xen.h,v 1.27 2008/02/19 13:25:53 bouyer Exp $ */ /* * @@ -62,6 +62,7 @@ void xennetback_init(void); void xen_shm_init(void); void xenevt_event(int); +void xenevt_setipending(int, int); void xenevt_notify(void); void idle_block(void); diff --git a/sys/arch/xen/x86/hypervisor_machdep.c b/sys/arch/xen/x86/hypervisor_machdep.c index e4bc9db43a07..8cf59380848c 100644 --- a/sys/arch/xen/x86/hypervisor_machdep.c +++ b/sys/arch/xen/x86/hypervisor_machdep.c @@ -1,4 +1,4 @@ -/* $NetBSD: hypervisor_machdep.c,v 1.4 2007/12/20 23:46:11 ad Exp $ */ +/* $NetBSD: hypervisor_machdep.c,v 1.5 2008/02/19 13:25:53 bouyer Exp $ */ /* * @@ -59,7 +59,7 @@ #include -__KERNEL_RCSID(0, "$NetBSD: hypervisor_machdep.c,v 1.4 2007/12/20 23:46:11 ad Exp $"); +__KERNEL_RCSID(0, "$NetBSD: hypervisor_machdep.c,v 1.5 2008/02/19 13:25:53 bouyer Exp $"); #include #include @@ -141,8 +141,10 @@ stipending() ret = 1; } #ifdef DOM0OPS - else - xenevt_event(port); + else { + /* set pending event */ + xenevt_setipending(l1i, l2i); + } #endif } } @@ -218,8 +220,18 @@ do_hypervisor_callback(struct intrframe *regs) if (evtsource[port]) call_evtchn_do_event(port, regs); #ifdef DOM0OPS - else - xenevt_event(port); + else { + if (ci->ci_ilevel < IPL_HIGH) { + /* fast path */ + int oipl = ci->ci_ilevel; + ci->ci_ilevel = IPL_HIGH; + xenevt_event(port); + ci->ci_ilevel = oipl; + } else { + /* set pending event */ + xenevt_setipending(l1i, l2i); + } + } #endif } } diff --git a/sys/arch/xen/xen/evtchn.c b/sys/arch/xen/xen/evtchn.c index 665d6c9027bd..d3467d2ed6e2 100644 --- a/sys/arch/xen/xen/evtchn.c +++ b/sys/arch/xen/xen/evtchn.c @@ -1,4 +1,4 @@ -/* $NetBSD: evtchn.c,v 1.30 2008/01/11 20:00:53 bouyer Exp $ */ +/* $NetBSD: evtchn.c,v 1.31 2008/02/19 13:25:53 bouyer Exp $ */ /* * Copyright (c) 2006 Manuel Bouyer. @@ -64,7 +64,7 @@ #include -__KERNEL_RCSID(0, "$NetBSD: evtchn.c,v 1.30 2008/01/11 20:00:53 bouyer Exp $"); +__KERNEL_RCSID(0, "$NetBSD: evtchn.c,v 1.31 2008/02/19 13:25:53 bouyer Exp $"); #include "opt_xen.h" #include "isa.h" @@ -449,10 +449,9 @@ int event_set_handler(int evtch, int (*func)(void *), void *arg, int level, const char *evname) { - struct iplsource *ipls; + struct cpu_info *ci = &cpu_info_primary; struct evtsource *evts; struct intrhand *ih, **ihp; - struct cpu_info *ci; int s; #ifdef IRQ_DEBUG @@ -482,22 +481,12 @@ event_set_handler(int evtch, int (*func)(void *), void *arg, int level, ih->ih_evt_next = NULL; ih->ih_ipl_next = NULL; - ci = &cpu_info_primary; s = splhigh(); - if (ci->ci_isources[level] == NULL) { - MALLOC(ipls, struct iplsource *, sizeof (struct iplsource), - M_DEVBUF, M_WAITOK|M_ZERO); - if (ipls == NULL) - panic("can't allocate fixed interrupt source"); - ipls->ipl_recurse = xenev_stubs[level].ist_recurse; - ipls->ipl_resume = xenev_stubs[level].ist_resume; - ipls->ipl_handlers = ih; - ci->ci_isources[level] = ipls; - } else { - ipls = ci->ci_isources[level]; - ih->ih_ipl_next = ipls->ipl_handlers; - ipls->ipl_handlers = ih; - } + + /* register handler for spllower() */ + event_set_iplhandler(ih, level); + + /* register handler for event channel */ if (evtsource[evtch] == NULL) { MALLOC(evts, struct evtsource *, sizeof (struct evtsource), M_DEVBUF, M_WAITOK|M_ZERO); @@ -536,6 +525,28 @@ event_set_handler(int evtch, int (*func)(void *), void *arg, int level, return 0; } +void +event_set_iplhandler(struct intrhand *ih, int level) +{ + struct cpu_info *ci = &cpu_info_primary; + struct iplsource *ipls; + + if (ci->ci_isources[level] == NULL) { + MALLOC(ipls, struct iplsource *, sizeof (struct iplsource), + M_DEVBUF, M_WAITOK|M_ZERO); + if (ipls == NULL) + panic("can't allocate fixed interrupt source"); + ipls->ipl_recurse = xenev_stubs[level].ist_recurse; + ipls->ipl_resume = xenev_stubs[level].ist_resume; + ipls->ipl_handlers = ih; + ci->ci_isources[level] = ipls; + } else { + ipls = ci->ci_isources[level]; + ih->ih_ipl_next = ipls->ipl_handlers; + ipls->ipl_handlers = ih; + } +} + int event_remove_handler(int evtch, int (*func)(void *), void *arg) { diff --git a/sys/arch/xen/xen/xenevt.c b/sys/arch/xen/xen/xenevt.c index 924739400799..437cbba56ba5 100644 --- a/sys/arch/xen/xen/xenevt.c +++ b/sys/arch/xen/xen/xenevt.c @@ -1,4 +1,4 @@ -/* $NetBSD: xenevt.c,v 1.20 2008/02/17 14:03:16 bouyer Exp $ */ +/* $NetBSD: xenevt.c,v 1.21 2008/02/19 13:25:53 bouyer Exp $ */ /* * Copyright (c) 2005 Manuel Bouyer. @@ -31,7 +31,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: xenevt.c,v 1.20 2008/02/17 14:03:16 bouyer Exp $"); +__KERNEL_RCSID(0, "$NetBSD: xenevt.c,v 1.21 2008/02/19 13:25:53 bouyer Exp $"); #include "opt_xen.h" #include @@ -136,22 +136,76 @@ STAILQ_HEAD(, xenevt_d) devevent_pending = static void xenevt_donotify(struct xenevt_d *); static void xenevt_record(struct xenevt_d *, evtchn_port_t); +/* pending events */ +long xenevt_ev1; +long xenevt_ev2[NR_EVENT_CHANNELS]; +static int xenevt_processevt(void *); + /* called at boot time */ void xenevtattach(int n) { + struct intrhand *ih; + int s; devevent_sih = softint_establish(SOFTINT_SERIAL, (void (*)(void *))xenevt_notify, NULL); memset(devevent, 0, sizeof(devevent)); + xenevt_ev1 = 0; + memset(xenevt_ev2, 0, sizeof(xenevt_ev2)); + + /* register a hanlder at splhigh, so that spllower() will call us */ + MALLOC(ih, struct intrhand *, sizeof (struct intrhand), M_DEVBUF, + M_WAITOK|M_ZERO); + if (ih == NULL) + panic("can't allocate xenevt interrupt source"); + ih->ih_fun = xenevt_processevt; + ih->ih_arg = NULL; + ih->ih_ipl_next = NULL; + s = splhigh(); + event_set_iplhandler(ih, IPL_HIGH); + splx(s); } -/* event callback */ +/* register pending event - always called with interrupt disabled */ +void +xenevt_setipending(int l1, int l2) +{ + xen_atomic_setbits_l(&xenevt_ev1, l1); + xen_atomic_setbits_l(&xenevt_ev2[l1], l2); + curcpu()->ci_ipending |= 1 << IPL_HIGH; +} + +/* process pending events */ +static int +xenevt_processevt(void *v) +{ + long l1, l2; + int l1i, l2i; + int port; + + l1 = xen_atomic_xchg(&xenevt_ev1, 0); + while ((l1i = ffs(l1)) != 0) { + l1i--; + l1 &= ~(1 << l1i); + l2 = xen_atomic_xchg(&xenevt_ev2[l1i], 0); + while ((l2i = ffs(l2)) != 0) { + l2i--; + l2 &= ~(1 << l2i); + port = (l1i << 5) + l2i; + xenevt_event(port); + } + } + + return 0; +} + + +/* event callback, called at splhigh() */ void xenevt_event(int port) { struct xenevt_d *d; - struct cpu_info *ci; d = devevent[port]; if (d != NULL) { @@ -161,18 +215,11 @@ xenevt_event(int port) return; } - ci = curcpu(); - - if (ci->ci_ilevel < IPL_SOFTSERIAL) { - /* fast and common path */ - xenevt_donotify(d); - } else { - simple_lock(&devevent_pending_lock); - STAILQ_INSERT_TAIL(&devevent_pending, d, pendingq); - simple_unlock(&devevent_pending_lock); - d->pending = true; - softint_schedule(devevent_sih); - } + simple_lock(&devevent_pending_lock); + STAILQ_INSERT_TAIL(&devevent_pending, d, pendingq); + simple_unlock(&devevent_pending_lock); + d->pending = true; + softint_schedule(devevent_sih); } } @@ -180,7 +227,7 @@ void xenevt_notify() { - cli(); + int s = splhigh(); simple_lock(&devevent_pending_lock); while (/* CONSTCOND */ 1) { struct xenevt_d *d; @@ -191,16 +238,16 @@ xenevt_notify() } STAILQ_REMOVE_HEAD(&devevent_pending, pendingq); simple_unlock(&devevent_pending_lock); - sti(); + splx(s); d->pending = false; xenevt_donotify(d); - cli(); + s = splhigh(); simple_lock(&devevent_pending_lock); } simple_unlock(&devevent_pending_lock); - sti(); + splx(s); } static void