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