Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/arch/xen/xen/evtchn.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/arch/xen/xen/evtchn.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.20 retrieving revision 1.20.24.3 diff -u -p -r1.20 -r1.20.24.3 --- src/sys/arch/xen/xen/evtchn.c 2006/12/08 15:05:18 1.20 +++ src/sys/arch/xen/xen/evtchn.c 2008/03/23 02:04:30 1.20.24.3 @@ -1,4 +1,4 @@ -/* $NetBSD: evtchn.c,v 1.20 2006/12/08 15:05:18 yamt Exp $ */ +/* evtchn.c,v 1.20.24.2 2008/01/09 01:50:18 matt Exp */ /* * Copyright (c) 2006 Manuel Bouyer. @@ -64,7 +64,7 @@ #include -__KERNEL_RCSID(0, "$NetBSD: evtchn.c,v 1.20 2006/12/08 15:05:18 yamt Exp $"); +__KERNEL_RCSID(0, "evtchn.c,v 1.20.24.2 2008/01/09 01:50:18 matt Exp"); #include "opt_xen.h" #include "isa.h" @@ -76,18 +76,19 @@ __KERNEL_RCSID(0, "$NetBSD: evtchn.c,v 1 #include #include #include +#include #include #include -#include -#include -#include +#include +#include +#include #ifndef XEN3 -#include +#include #endif -#include +#include /* * This lock protects updates to the following mapping and reference-count @@ -116,8 +117,7 @@ physdev_op_t physdev_op_notify = { }; #endif -int debug_port; -int xen_debug_handler(void *); +int debug_port = -1; #ifndef XEN3 static int xen_misdirect_handler(void *); #endif @@ -153,20 +153,13 @@ events_default_setup() void init_events() { +#ifndef XEN3 int evtch; - evtch = bind_virq_to_evtch(VIRQ_DEBUG); - aprint_verbose("debug virtual interrupt using event channel %d\n", - evtch); - event_set_handler(evtch, &xen_debug_handler, NULL, IPL_DEBUG, - "debugev"); - hypervisor_enable_event(evtch); - -#ifndef XEN3 evtch = bind_virq_to_evtch(VIRQ_MISDIRECT); aprint_verbose("misdirect virtual interrupt using event channel %d\n", evtch); - event_set_handler(evtch, &xen_misdirect_handler, NULL, IPL_DIE, + event_set_handler(evtch, &xen_misdirect_handler, NULL, IPL_HIGH, "misdirev"); hypervisor_enable_event(evtch); @@ -174,8 +167,18 @@ init_events() * alive. */ ctrl_if_init(); #endif + debug_port = bind_virq_to_evtch(VIRQ_DEBUG); + aprint_verbose("debug virtual interrupt using event channel %d\n", + debug_port); + /* + * Don't call event_set_handler(), we'll use a shortcut. Just set + * evtsource[] to a non-NULL value so that evtchn_do_event will + * be called. + */ + evtsource[debug_port] = (void *)-1; + hypervisor_enable_event(debug_port); - enable_intr(); /* at long last... */ + x86_enable_intr(); /* at long last... */ } unsigned int @@ -187,6 +190,8 @@ evtchn_do_event(int evtch, struct intrfr int (*ih_fun)(void *, void *); extern struct uvmexp uvmexp; u_int32_t iplmask; + int i; + u_int32_t iplbit; #ifdef DIAGNOSTIC if (evtch >= NR_EVENT_CHANNELS) { @@ -205,8 +210,7 @@ evtchn_do_event(int evtch, struct intrfr * Shortcut for the debug handler, we want it to always run, * regardless of the IPL level. */ - - if (evtch == debug_port) { + if (__predict_false(evtch == debug_port)) { xen_debug_handler(NULL); hypervisor_enable_event(evtch); return 0; @@ -227,7 +231,7 @@ evtchn_do_event(int evtch, struct intrfr evtch, evtsource[evtch]->ev_maxlevel, ilevel); #endif hypervisor_set_ipending(evtsource[evtch]->ev_imask, - evtch / 32, evtch % 32); + evtch >> LONG_SHIFT, evtch & LONG_MASK); /* leave masked */ return 0; } @@ -249,10 +253,9 @@ evtchn_do_event(int evtch, struct intrfr #endif cli(); hypervisor_set_ipending(iplmask, - evtch / 32, evtch % 32); + evtch >> LONG_SHIFT, evtch & LONG_MASK); /* leave masked */ - splx(ilevel); - return 0; + goto splx; } iplmask &= ~IUNMASK(ci, ih->ih_level); ci->ci_ilevel = ih->ih_level; @@ -265,8 +268,36 @@ evtchn_do_event(int evtch, struct intrfr x86_intunlock(regs); #endif hypervisor_enable_event(evtch); - splx(ilevel); - +splx: + /* + * C version of spllower(). ASTs will be checked when + * hypevisor_callback() exits, so no need to check here. + */ + iplbit = 1 << (NIPL - 1); + i = (NIPL - 1); + while ((iplmask = (IUNMASK(ci, ilevel) & ci->ci_ipending)) != 0) { + if (iplbit == 0) { + /* another pending ipl went in while running a handler*/ + iplbit = 1 << (NIPL - 1); + i = (NIPL - 1); + } + if (iplmask & iplbit) { + ci->ci_ipending &= ~iplbit; + KASSERT(i > ilevel); + ci->ci_ilevel = i; + for (ih = ci->ci_isources[i]->ipl_handlers; ih != NULL; + ih = ih->ih_ipl_next) { + sti(); + ih_fun = (void *)ih->ih_fun; + ih_fun(ih->ih_arg, regs); + cli(); + } + hypervisor_enable_ipl(i); + } + i--; + iplbit >>= 1; + } + ci->ci_ilevel = ilevel; return 0; } @@ -289,8 +320,6 @@ bind_virq_to_evtch(int virq) if (HYPERVISOR_event_channel_op(&op) != 0) panic("Failed to bind virtual IRQ %d\n", virq); evtchn = op.u.bind_virq.port; - if (virq == VIRQ_DEBUG) - debug_port = evtchn; virq_to_evtch[virq] = evtchn; } @@ -449,10 +478,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 +510,12 @@ event_set_handler(int evtch, int (*func) 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 +554,28 @@ event_set_handler(int evtch, int (*func) 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) { @@ -605,14 +645,18 @@ xen_debug_handler(void *arg) { struct cpu_info *ci = curcpu(); int i; - int ci_ilevel = ci->ci_ilevel; - int ci_ipending = ci->ci_ipending; - int ci_idepth = ci->ci_idepth; + int xci_ilevel = ci->ci_ilevel; + int xci_ipending = ci->ci_ipending; + int xci_idepth = ci->ci_idepth; u_long upcall_pending = - HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_pending; + HYPERVISOR_shared_info->vcpu_info[0].evtchn_upcall_pending; u_long upcall_mask = - HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_mask; + HYPERVISOR_shared_info->vcpu_info[0].evtchn_upcall_mask; +#ifdef XEN3 + u_long pending_sel = HYPERVISOR_shared_info->vcpu_info[0].evtchn_pending_sel; +#else u_long pending_sel = HYPERVISOR_shared_info->evtchn_pending_sel; +#endif unsigned long evtchn_mask[sizeof(unsigned long) * 8]; unsigned long evtchn_pending[sizeof(unsigned long) * 8]; @@ -626,16 +670,16 @@ xen_debug_handler(void *arg) __insn_barrier(); printf("debug event\n"); printf("ci_ilevel 0x%x ci_ipending 0x%x ci_idepth %d\n", - ci_ilevel, ci_ipending, ci_idepth); + xci_ilevel, xci_ipending, xci_idepth); printf("evtchn_upcall_pending %ld evtchn_upcall_mask %ld" " evtchn_pending_sel 0x%lx\n", upcall_pending, upcall_mask, pending_sel); printf("evtchn_mask"); - for (i = 0 ; i < 32; i++) + for (i = 0 ; i <= LONG_MASK; i++) printf(" %lx", (u_long)evtchn_mask[i]); printf("\n"); printf("evtchn_pending"); - for (i = 0 ; i < 32; i++) + for (i = 0 ; i <= LONG_MASK; i++) printf(" %lx", (u_long)evtchn_pending[i]); printf("\n"); return 0;