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.
This commit is contained in:
bouyer 2008-02-19 13:25:53 +00:00
parent b1eaff3725
commit e3e720d87d
5 changed files with 121 additions and 47 deletions

View File

@ -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 *);

View File

@ -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);

View File

@ -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 <sys/cdefs.h>
__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 <sys/param.h>
#include <sys/systm.h>
@ -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
}
}

View File

@ -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 <sys/cdefs.h>
__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)
{

View File

@ -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 <sys/cdefs.h>
__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 <sys/param.h>
@ -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