Module Name: src Committed By: bouyer Date: Thu May 7 19:48:58 UTC 2020
Modified Files: src/sys/arch/xen/include: evtchn.h src/sys/arch/xen/x86: xen_intr.c xen_ipi.c src/sys/arch/xen/xen: evtchn.c xen_clock.c Log Message: Change event_set_handler() to take the target CPU parameter. If ci is NULL, event_set_handler() will choose the CPU and bind the event. If ci is not NULL the caller is responsible for binding the event. Use a IPI xcall to register the handlers if needed. pull in a hack from x86 to force pirq handlers to be mpsafe if registered at a level != IPL_VM. This is for the com at isa interrupt handler, which registers at IPL_HIGH and has to way to tell it's mpsafe (taking KERNEL_LOCK at IPL_HIGH causes deadlocks on MP systems). To generate a diff of this commit: cvs rdiff -u -r1.31 -r1.32 src/sys/arch/xen/include/evtchn.h cvs rdiff -u -r1.26 -r1.27 src/sys/arch/xen/x86/xen_intr.c cvs rdiff -u -r1.38 -r1.39 src/sys/arch/xen/x86/xen_ipi.c cvs rdiff -u -r1.93 -r1.94 src/sys/arch/xen/xen/evtchn.c cvs rdiff -u -r1.4 -r1.5 src/sys/arch/xen/xen/xen_clock.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.31 src/sys/arch/xen/include/evtchn.h:1.32 --- src/sys/arch/xen/include/evtchn.h:1.31 Mon May 4 15:55:56 2020 +++ src/sys/arch/xen/include/evtchn.h Thu May 7 19:48:58 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: evtchn.h,v 1.31 2020/05/04 15:55:56 jdolecek Exp $ */ +/* $NetBSD: evtchn.h,v 1.32 2020/05/07 19:48:58 bouyer Exp $ */ /* * @@ -40,12 +40,11 @@ unsigned int evtchn_do_event(int, struct void call_evtchn_do_event(int, struct intrframe *); void call_xenevt_event(int); struct intrhand *event_set_handler(int, int (*func)(void *), void *, - int, const char *, const char *, bool, bool); + int, const char *, const char *, bool, struct cpu_info *); int event_remove_handler(int, int (*func)(void *), void *); struct cpu_info; struct intrhand; -void event_set_iplhandler(struct cpu_info *, struct intrhand *, int); extern int debug_port; extern int xen_debug_handler(void *); Index: src/sys/arch/xen/x86/xen_intr.c diff -u src/sys/arch/xen/x86/xen_intr.c:1.26 src/sys/arch/xen/x86/xen_intr.c:1.27 --- src/sys/arch/xen/x86/xen_intr.c:1.26 Tue May 5 17:02:01 2020 +++ src/sys/arch/xen/x86/xen_intr.c Thu May 7 19:48:58 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: xen_intr.c,v 1.26 2020/05/05 17:02:01 bouyer Exp $ */ +/* $NetBSD: xen_intr.c,v 1.27 2020/05/07 19:48:58 bouyer Exp $ */ /*- * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: xen_intr.c,v 1.26 2020/05/05 17:02:01 bouyer Exp $"); +__KERNEL_RCSID(0, "$NetBSD: xen_intr.c,v 1.27 2020/05/07 19:48:58 bouyer Exp $"); #include "opt_multiprocessor.h" @@ -143,7 +143,7 @@ xen_intr_establish_xname(int legacy_irq, sizeof(intrstr_buf)); rih = event_set_handler(pin, handler, arg, level, - intrstr, xname, known_mpsafe, true); + intrstr, xname, known_mpsafe, NULL); if (rih == NULL) { printf("%s: can't establish interrupt\n", __func__); @@ -157,6 +157,8 @@ xen_intr_establish_xname(int legacy_irq, struct pintrhand *pih; int gsi; int evtchn; + /* the hack below is from x86's intr_establish_xname() */ + bool mpsafe = (known_mpsafe || level != IPL_VM); KASSERTMSG(legacy_irq == -1 || (0 <= legacy_irq && legacy_irq < NUM_XEN_IRQS), "bad legacy IRQ value: %d", legacy_irq); @@ -190,7 +192,7 @@ xen_intr_establish_xname(int legacy_irq, } pih = pirq_establish(gsi, evtchn, handler, arg, level, - intrstr, xname, known_mpsafe); + intrstr, xname, mpsafe); pih->pic = pic; return pih; #endif /* NPCI > 0 || NISA > 0 */ Index: src/sys/arch/xen/x86/xen_ipi.c diff -u src/sys/arch/xen/x86/xen_ipi.c:1.38 src/sys/arch/xen/x86/xen_ipi.c:1.39 --- src/sys/arch/xen/x86/xen_ipi.c:1.38 Sat Apr 25 15:26:17 2020 +++ src/sys/arch/xen/x86/xen_ipi.c Thu May 7 19:48:58 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: xen_ipi.c,v 1.38 2020/04/25 15:26:17 bouyer Exp $ */ +/* $NetBSD: xen_ipi.c,v 1.39 2020/05/07 19:48:58 bouyer Exp $ */ /*- * Copyright (c) 2011, 2019 The NetBSD Foundation, Inc. @@ -35,7 +35,7 @@ * Based on: x86/ipi.c */ -__KERNEL_RCSID(0, "$NetBSD: xen_ipi.c,v 1.38 2020/04/25 15:26:17 bouyer Exp $"); +__KERNEL_RCSID(0, "$NetBSD: xen_ipi.c,v 1.39 2020/05/07 19:48:58 bouyer Exp $"); #include "opt_ddb.h" @@ -143,7 +143,7 @@ xen_ipi_init(void) device_xname(ci->ci_dev)); if (event_set_handler(evtchn, xen_ipi_handler, ci, IPL_HIGH, NULL, - intr_xname, true, false) == NULL) { + intr_xname, true, ci) == NULL) { panic("%s: unable to register ipi handler\n", __func__); /* NOTREACHED */ } Index: src/sys/arch/xen/xen/evtchn.c diff -u src/sys/arch/xen/xen/evtchn.c:1.93 src/sys/arch/xen/xen/evtchn.c:1.94 --- src/sys/arch/xen/xen/evtchn.c:1.93 Wed May 6 13:43:48 2020 +++ src/sys/arch/xen/xen/evtchn.c Thu May 7 19:48:57 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: evtchn.c,v 1.93 2020/05/06 13:43:48 bouyer Exp $ */ +/* $NetBSD: evtchn.c,v 1.94 2020/05/07 19:48:57 bouyer Exp $ */ /* * Copyright (c) 2006 Manuel Bouyer. @@ -54,7 +54,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: evtchn.c,v 1.93 2020/05/06 13:43:48 bouyer Exp $"); +__KERNEL_RCSID(0, "$NetBSD: evtchn.c,v 1.94 2020/05/07 19:48:57 bouyer Exp $"); #include "opt_xen.h" #include "isa.h" @@ -722,7 +722,7 @@ pirq_establish(int pirq, int evtch, int ih->arg = arg; if (event_set_handler(evtch, pirq_interrupt, ih, level, intrname, - xname, known_mpsafe, true) == NULL) { + xname, known_mpsafe, NULL) == NULL) { kmem_free(ih, sizeof(struct pintrhand)); return NULL; } @@ -784,14 +784,81 @@ intr_calculatemasks(struct evtsource *ev xen_atomic_clear_bit(&curcpu()->ci_evtmask[0], evtch); } + +struct event_set_handler_args { + struct intrhand *ih; + struct intrsource *ipls; + struct evtsource *evts; + int evtch; +}; + +/* + * Called on bound CPU to handle event_set_handler() + * caller (on initiating CPU) holds cpu_lock on our behalf + * arg1: struct event_set_handler_args * + * arg2: NULL + */ + +static void +event_set_handler_xcall(void *arg1, void *arg2) +{ + struct event_set_handler_args *esh_args = arg1; + struct intrhand **ihp, *ih = esh_args->ih; + struct evtsource *evts = esh_args->evts; + + const u_long psl = x86_read_psl(); + x86_disable_intr(); + /* sort by IPL order, higher first */ + for (ihp = &evts->ev_handlers; *ihp != NULL; + ihp = &((*ihp)->ih_evt_next)) { + if ((*ihp)->ih_level < ih->ih_level) + break; + } + /* insert before *ihp */ + ih->ih_evt_next = *ihp; + *ihp = ih; +#ifndef XENPV + evts->ev_isl->is_handlers = evts->ev_handlers; +#endif + /* register per-cpu handler for spllower() */ + struct cpu_info *ci = ih->ih_cpu; + int sir = XEN_IPL2SIR(ih->ih_level); + KASSERT(sir >= SIR_XENIPL_VM && sir <= SIR_XENIPL_HIGH); + + KASSERT(ci == curcpu()); + if (ci->ci_isources[sir] == NULL) { + KASSERT(esh_args->ipls != NULL); + ci->ci_isources[sir] = esh_args->ipls; + } + struct intrsource *ipls = ci->ci_isources[sir]; + ih->ih_next = ipls->is_handlers; + ipls->is_handlers = ih; + x86_intr_calculatemasks(ci); + + intr_calculatemasks(evts, esh_args->evtch, ci); + x86_write_psl(psl); +} + struct intrhand * event_set_handler(int evtch, int (*func)(void *), void *arg, int level, - const char *intrname, const char *xname, bool mpsafe, bool bind) + const char *intrname, const char *xname, bool mpsafe, struct cpu_info *ci) { - struct cpu_info *ci = curcpu(); /* XXX: pass in ci ? */ - struct evtsource *evts; - struct intrhand *ih, **ihp; + struct event_set_handler_args esh_args; char intrstr_buf[INTRIDBUF]; + bool bind = false; + + memset(&esh_args, 0, sizeof(esh_args)); + + /* + * if ci is not specified, we bind to the current cpu. + * if ci has been proviced by the called, we assume + * he will do the EVTCHNOP_bind_vcpu if needed. + */ + if (ci == NULL) { + ci = curcpu(); + bind = true; + } + #ifdef IRQ_DEBUG printf("event_set_handler IRQ %d handler %p\n", evtch, func); @@ -806,29 +873,47 @@ event_set_handler(int evtch, int (*func) printf("event_set_handler evtch %d handler %p level %d\n", evtch, handler, level); #endif - ih = kmem_zalloc(sizeof (struct intrhand), KM_NOSLEEP); - if (ih == NULL) + esh_args.ih = kmem_zalloc(sizeof (struct intrhand), KM_NOSLEEP); + if (esh_args.ih == NULL) panic("can't allocate fixed interrupt source"); - ih->ih_pic = &xen_pic; - ih->ih_level = level; - ih->ih_fun = ih->ih_realfun = func; - ih->ih_arg = ih->ih_realarg = arg; - ih->ih_evt_next = NULL; - ih->ih_next = NULL; - ih->ih_cpu = ci; - ih->ih_pin = evtch; + esh_args.ih->ih_pic = &xen_pic; + esh_args.ih->ih_level = level; + esh_args.ih->ih_fun = esh_args.ih->ih_realfun = func; + esh_args.ih->ih_arg = esh_args.ih->ih_realarg = arg; + esh_args.ih->ih_evt_next = NULL; + esh_args.ih->ih_next = NULL; + esh_args.ih->ih_cpu = ci; + esh_args.ih->ih_pin = evtch; #ifdef MULTIPROCESSOR if (!mpsafe) { - ih->ih_fun = xen_intr_biglock_wrapper; - ih->ih_arg = ih; + esh_args.ih->ih_fun = xen_intr_biglock_wrapper; + esh_args.ih->ih_arg = esh_args.ih; } #endif /* MULTIPROCESSOR */ + KASSERT(mpsafe || level < IPL_HIGH); mutex_enter(&cpu_lock); + /* allocate IPL source if needed */ + int sir = XEN_IPL2SIR(level); + if (ci->ci_isources[sir] == NULL) { + struct intrsource *ipls; + ipls = kmem_zalloc(sizeof (struct intrsource), KM_NOSLEEP); + if (ipls == NULL) + panic("can't allocate fixed interrupt source"); + ipls->is_recurse = xenev_stubs[level - IPL_VM].ist_recurse; + ipls->is_resume = xenev_stubs[level - IPL_VM].ist_resume; + ipls->is_pic = &xen_pic; + esh_args.ipls = ipls; + /* + * note that we can't set ci_isources here, as + * the assembly can't handle is_handlers being NULL + */ + } /* register handler for event channel */ if (evtsource[evtch] == NULL) { + struct evtsource *evts; evtchn_op_t op; if (intrname == NULL) intrname = intr_create_intrid(-1, &xen_pic, evtch, @@ -838,15 +923,7 @@ event_set_handler(int evtch, int (*func) if (evts == NULL) 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; - evtsource[evtch] = evts; strlcpy(evts->ev_intrname, intrname, sizeof(evts->ev_intrname)); evcnt_attach_dynamic(&evts->ev_evcnt, EVCNT_TYPE_INTR, NULL, @@ -864,70 +941,31 @@ event_set_handler(int evtch, int (*func) #ifndef XENPV evts->ev_isl = intr_allocate_io_intrsource(intrname); evts->ev_isl->is_pic = &xen_pic; - evts->ev_isl->is_handlers = evts->ev_handlers; -#endif - } else { - evts = evtsource[evtch]; - /* sort by IPL order, higher first */ - for (ihp = &evts->ev_handlers; ; ihp = &((*ihp)->ih_evt_next)) { - if ((*ihp)->ih_level < ih->ih_level) { - /* insert before *ihp */ - ih->ih_evt_next = *ihp; - *ihp = ih; - break; - } - if ((*ihp)->ih_evt_next == NULL) { - (*ihp)->ih_evt_next = ih; - break; - } - } -#ifndef XENPV - evts->ev_isl->is_handlers = evts->ev_handlers; #endif + evtsource[evtch] = evts; } - const u_long psl = x86_read_psl(); - x86_disable_intr(); - /* register per-cpu handler for spllower() */ - event_set_iplhandler(ci, ih, level); - intr_calculatemasks(evts, evtch, ci); - x86_write_psl(psl); + esh_args.evts = evtsource[evtch]; // append device name - if (evts->ev_xname[0] != '\0') - strlcat(evts->ev_xname, ", ", sizeof(evts->ev_xname)); - strlcat(evts->ev_xname, xname, sizeof(evts->ev_xname)); - - mutex_exit(&cpu_lock); - return ih; -} + if (esh_args.evts->ev_xname[0] != '\0') { + strlcat(esh_args.evts->ev_xname, ", ", + sizeof(esh_args.evts->ev_xname)); + } + strlcat(esh_args.evts->ev_xname, xname, + sizeof(esh_args.evts->ev_xname)); -void -event_set_iplhandler(struct cpu_info *ci, - struct intrhand *ih, - int level) -{ - struct intrsource *ipls; - int sir = XEN_IPL2SIR(level); - KASSERT(sir >= SIR_XENIPL_VM && sir <= SIR_XENIPL_HIGH); + esh_args.evtch = evtch; - KASSERT(ci == ih->ih_cpu); - KASSERT(ci == curcpu()); - if (ci->ci_isources[sir] == NULL) { - ipls = kmem_zalloc(sizeof (struct intrsource), - KM_NOSLEEP); - if (ipls == NULL) - panic("can't allocate fixed interrupt source"); - ipls->is_recurse = xenev_stubs[level - IPL_VM].ist_recurse; - ipls->is_resume = xenev_stubs[level - IPL_VM].ist_resume; - ipls->is_handlers = ih; - ipls->is_pic = &xen_pic; - ci->ci_isources[sir] = ipls; + if (ci == curcpu() || !mp_online) { + event_set_handler_xcall(&esh_args, NULL); } else { - ipls = ci->ci_isources[sir]; - ih->ih_next = ipls->is_handlers; - ipls->is_handlers = ih; + uint64_t where = xc_unicast(0, event_set_handler_xcall, + &esh_args, NULL, ci); + xc_wait(where); } - x86_intr_calculatemasks(ci); + + mutex_exit(&cpu_lock); + return esh_args.ih; } /* Index: src/sys/arch/xen/xen/xen_clock.c diff -u src/sys/arch/xen/xen/xen_clock.c:1.4 src/sys/arch/xen/xen/xen_clock.c:1.5 --- src/sys/arch/xen/xen/xen_clock.c:1.4 Sat May 2 16:44:36 2020 +++ src/sys/arch/xen/xen/xen_clock.c Thu May 7 19:48:57 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: xen_clock.c,v 1.4 2020/05/02 16:44:36 bouyer Exp $ */ +/* $NetBSD: xen_clock.c,v 1.5 2020/05/07 19:48:57 bouyer Exp $ */ /*- * Copyright (c) 2017, 2018 The NetBSD Foundation, Inc. @@ -36,7 +36,7 @@ #endif #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: xen_clock.c,v 1.4 2020/05/02 16:44:36 bouyer Exp $"); +__KERNEL_RCSID(0, "$NetBSD: xen_clock.c,v 1.5 2020/05/07 19:48:57 bouyer Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -636,7 +636,7 @@ xen_resumeclocks(struct cpu_info *ci) /* XXX sketchy function pointer cast -- fix the API, please */ if (event_set_handler(evtch, __FPTRCAST(int (*)(void *), xen_timer_handler), - ci, IPL_CLOCK, NULL, intr_xname, true, false) == NULL) + ci, IPL_CLOCK, NULL, intr_xname, true, ci) == NULL) panic("failed to establish timer interrupt handler"); hypervisor_unmask_event(evtch);