Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/xen Make event/interrupt handling MP aware
details: https://anonhg.NetBSD.org/src/rev/fe6800ea3670
branches: trunk
changeset: 768199:fe6800ea3670
user: cherry <cherry%NetBSD.org@localhost>
date: Thu Aug 11 17:58:59 2011 +0000
description:
Make event/interrupt handling MP aware
diffstat:
sys/arch/xen/include/evtchn.h | 7 +-
sys/arch/xen/include/intr.h | 10 +-
sys/arch/xen/x86/intr.c | 21 +---
sys/arch/xen/xen/evtchn.c | 213 +++++++++++++++++++++++++++++++++++------
sys/arch/xen/xen/xenevt.c | 9 +-
5 files changed, 195 insertions(+), 65 deletions(-)
diffs (truncated from 629 to 300 lines):
diff -r 6e4be852e170 -r fe6800ea3670 sys/arch/xen/include/evtchn.h
--- a/sys/arch/xen/include/evtchn.h Thu Aug 11 17:14:42 2011 +0000
+++ b/sys/arch/xen/include/evtchn.h Thu Aug 11 17:58:59 2011 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: evtchn.h,v 1.18 2009/10/23 02:32:33 snj Exp $ */
+/* $NetBSD: evtchn.h,v 1.19 2011/08/11 17:58:59 cherry Exp $ */
/*
*
@@ -41,8 +41,9 @@
int event_set_handler(int, int (*func)(void *), void *, int, const char *);
int event_remove_handler(int, int (*func)(void *), void *);
+struct cpu_info;
struct intrhand;
-void event_set_iplhandler(struct intrhand *, int);
+void event_set_iplhandler(struct cpu_info *, struct intrhand *, int);
extern int debug_port;
extern int xen_debug_handler(void *);
@@ -52,6 +53,8 @@
int unbind_pirq_from_evtch(int);
int unbind_virq_from_evtch(int);
+evtchn_port_t bind_vcpu_to_evtch(cpuid_t);
+
struct pintrhand {
int pirq;
int evtch;
diff -r 6e4be852e170 -r fe6800ea3670 sys/arch/xen/include/intr.h
--- a/sys/arch/xen/include/intr.h Thu Aug 11 17:14:42 2011 +0000
+++ b/sys/arch/xen/include/intr.h Thu Aug 11 17:58:59 2011 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: intr.h,v 1.32 2011/08/10 11:39:45 cherry Exp $ */
+/* $NetBSD: intr.h,v 1.33 2011/08/11 17:58:59 cherry Exp $ */
/* NetBSD intr.h,v 1.15 2004/10/31 10:39:34 yamt Exp */
/*-
@@ -54,6 +54,7 @@
uint32_t ev_imask; /* interrupt mask */
struct intrhand *ev_handlers; /* handler chain */
struct evcnt ev_evcnt; /* interrupt counter */
+ struct cpu_info *ev_cpu; /* cpu on which this event is bound */
char ev_evname[32]; /* event counter name */
};
@@ -161,7 +162,6 @@
void intr_default_setup(void);
int x86_nmi(void);
-void intr_calculatemasks(struct evtsource *);
void *intr_establish(int, struct pic *, int, int, int, int (*)(void *), void *, bool);
void intr_disestablish(struct intrhand *);
@@ -180,9 +180,9 @@
int xen_send_ipi(struct cpu_info *, uint32_t);
void xen_broadcast_ipi(uint32_t);
#else
-#define xen_ipi_init(_1) do {} while(0) /* nothing */
-#define xen_send_ipi(_i1, _i2) do {} while(0) /* nothing */
-#define xen_broadcast_ipi(_i1) do {} while(0) /* nothing */
+#define xen_ipi_init(_1) ((void) 0) /* nothing */
+#define xen_send_ipi(_i1, _i2) (0) /* nothing */
+#define xen_broadcast_ipi(_i1) ((void) 0) /* nothing */
#endif /* MULTIPROCESSOR */
#endif /* !_LOCORE */
diff -r 6e4be852e170 -r fe6800ea3670 sys/arch/xen/x86/intr.c
--- a/sys/arch/xen/x86/intr.c Thu Aug 11 17:14:42 2011 +0000
+++ b/sys/arch/xen/x86/intr.c Thu Aug 11 17:58:59 2011 +0000
@@ -103,7 +103,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.27 2010/03/19 23:27:12 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.28 2011/08/11 17:59:00 cherry Exp $");
#include "opt_multiprocessor.h"
#include "opt_xen.h"
@@ -119,6 +119,7 @@
#include <sys/proc.h>
#include <sys/errno.h>
#include <sys/cpu.h>
+#include <sys/simplelock.h>
#include <uvm/uvm_extern.h>
@@ -153,24 +154,6 @@
#endif
/*
- * Recalculate the interrupt from scratch for an event source.
- */
-void
-intr_calculatemasks(struct evtsource *evts)
-{
- struct intrhand *ih;
-
- evts->ev_maxlevel = IPL_NONE;
- evts->ev_imask = 0;
- for (ih = evts->ev_handlers; ih != NULL; ih = ih->ih_evt_next) {
- if (ih->ih_level > evts->ev_maxlevel)
- evts->ev_maxlevel = ih->ih_level;
- evts->ev_imask |= (1 << ih->ih_level);
- }
-
-}
-
-/*
* Fake interrupt handler structures for the benefit of symmetry with
* other interrupt sources.
*/
diff -r 6e4be852e170 -r fe6800ea3670 sys/arch/xen/xen/evtchn.c
--- a/sys/arch/xen/xen/evtchn.c Thu Aug 11 17:14:42 2011 +0000
+++ b/sys/arch/xen/xen/evtchn.c Thu Aug 11 17:58:59 2011 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: evtchn.c,v 1.49 2011/08/10 21:46:02 cherry Exp $ */
+/* $NetBSD: evtchn.c,v 1.50 2011/08/11 17:59:00 cherry Exp $ */
/*
* Copyright (c) 2006 Manuel Bouyer.
@@ -54,20 +54,21 @@
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: evtchn.c,v 1.49 2011/08/10 21:46:02 cherry Exp $");
+__KERNEL_RCSID(0, "$NetBSD: evtchn.c,v 1.50 2011/08/11 17:59:00 cherry Exp $");
#include "opt_xen.h"
#include "isa.h"
#include "pci.h"
#include <sys/param.h>
+#include <sys/cpu.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/proc.h>
#include <sys/malloc.h>
#include <sys/reboot.h>
-#include <sys/simplelock.h>
+#include <sys/mutex.h>
#include <uvm/uvm.h>
@@ -82,14 +83,23 @@
* This lock protects updates to the following mapping and reference-count
* arrays. The lock does not need to be acquired to read the mapping tables.
*/
-static struct simplelock irq_mapping_update_lock = SIMPLELOCK_INITIALIZER;
+static kmutex_t evtchn_lock;
/* event handlers */
struct evtsource *evtsource[NR_EVENT_CHANNELS];
-/* Reference counts for bindings to event channels */
+/* channel locks */
+static 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];
+/* event-channel <-> VCPU mapping for IPIs. XXX: redo for SMP. */
+static evtchn_port_t vcpu_ipi_to_evtch[MAX_VIRT_CPUS];
+
+/* event-channel <-> VCPU mapping for VIRQ_TIMER. XXX: redo for SMP. */
+static int virq_timer_to_evtch[MAX_VIRT_CPUS];
+
/* event-channel <-> VIRQ mapping. */
static int virq_to_evtch[NR_VIRQS];
@@ -137,6 +147,14 @@
{
int i;
+ /* No VCPU -> event mappings. */
+ for (i = 0; i < MAX_VIRT_CPUS; i++)
+ vcpu_ipi_to_evtch[i] = -1;
+
+ /* No VIRQ_TIMER -> event mappings. */
+ for (i = 0; i < MAX_VIRT_CPUS; i++)
+ virq_timer_to_evtch[i] = -1;
+
/* No VIRQ -> event mappings. */
for (i = 0; i < NR_VIRQS; i++)
virq_to_evtch[i] = -1;
@@ -162,6 +180,8 @@
events_init(void)
{
debug_port = bind_virq_to_evtch(VIRQ_DEBUG);
+ KASSERT(debug_port != -1);
+
aprint_verbose("debug virtual interrupt using event channel %d\n",
debug_port);
/*
@@ -197,7 +217,7 @@
if (evtch == IRQ_DEBUG)
printf("evtchn_do_event: evtch %d\n", evtch);
#endif
- ci = &cpu_info_primary;
+ ci = curcpu();
/*
* Shortcut for the debug handler, we want it to always run,
@@ -217,31 +237,46 @@
ci->ci_data.cpu_nintr++;
evtsource[evtch]->ev_evcnt.ev_count++;
ilevel = ci->ci_ilevel;
- if (evtsource[evtch]->ev_maxlevel <= ilevel) {
+ if (evtsource[evtch]->ev_maxlevel <= ilevel ||
+ evtsource[evtch]->ev_cpu != ci /* XXX: get stats */) {
#ifdef IRQ_DEBUG
if (evtch == IRQ_DEBUG)
printf("evtsource[%d]->ev_maxlevel %d <= ilevel %d\n",
evtch, evtsource[evtch]->ev_maxlevel, ilevel);
#endif
- hypervisor_set_ipending(ci, evtsource[evtch]->ev_imask,
- evtch >> LONG_SHIFT, evtch & LONG_MASK);
- /* leave masked */
+ hypervisor_set_ipending(evtsource[evtch]->ev_cpu,
+ evtsource[evtch]->ev_imask,
+ evtch >> LONG_SHIFT,
+ evtch & LONG_MASK);
+
+ if (evtsource[evtch]->ev_cpu != ci) {
+ /* facilitate spllower() on remote cpu */
+ struct cpu_info *rci = evtsource[evtch]->ev_cpu;
+ if (xen_send_ipi(rci, XEN_IPI_KICK) != 0) {
+ panic("xen_send_ipi(%s, XEN_IPI_KICK) failed\n", cpu_name(rci));
+ }
+ }
+
+ /* leave masked */
return 0;
}
ci->ci_ilevel = evtsource[evtch]->ev_maxlevel;
iplmask = evtsource[evtch]->ev_imask;
sti();
+ mutex_spin_enter(&evtlock[evtch]);
ih = evtsource[evtch]->ev_handlers;
while (ih != NULL) {
- if (ih->ih_level <= ilevel) {
+ if (ih->ih_level <= ilevel ||
+ ih->ih_cpu != ci) {
#ifdef IRQ_DEBUG
if (evtch == IRQ_DEBUG)
printf("ih->ih_level %d <= ilevel %d\n", ih->ih_level, ilevel);
#endif
cli();
- hypervisor_set_ipending(ci, iplmask,
+ hypervisor_set_ipending(ih->ih_cpu, iplmask,
evtch >> LONG_SHIFT, evtch & LONG_MASK);
/* leave masked */
+ mutex_spin_exit(&evtlock[evtch]);
goto splx;
}
iplmask &= ~IUNMASK(ci, ih->ih_level);
@@ -250,6 +285,7 @@
ih_fun(ih->ih_arg, regs);
ih = ih->ih_evt_next;
}
+ mutex_spin_exit(&evtlock[evtch]);
cli();
hypervisor_enable_event(evtch);
splx:
@@ -267,6 +303,7 @@
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);
@@ -292,6 +329,37 @@
return 0;
}
+#define PRIuCPUID "lu" /* XXX: move this somewhere more appropriate */
+
+evtchn_port_t
+bind_vcpu_to_evtch(cpuid_t vcpu)
+{
+ evtchn_op_t op;
+ evtchn_port_t evtchn;
+ int s;
+
+ s = splhigh();
+ mutex_spin_enter(&evtchn_lock);
+
+ evtchn = vcpu_ipi_to_evtch[vcpu];
+ if (evtchn == -1) {
+ op.cmd = EVTCHNOP_bind_ipi;
+ op.u.bind_ipi.vcpu = (uint32_t) vcpu;
+ if (HYPERVISOR_event_channel_op(&op) != 0)
+ panic("Failed to bind ipi to VCPU %"PRIuCPUID"\n", vcpu);
+ evtchn = op.u.bind_ipi.port;
+
+ vcpu_ipi_to_evtch[vcpu] = evtchn;
+ }
+
Home |
Main Index |
Thread Index |
Old Index