Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch Add a PIC_XEN abstraction to evtchn.c



details:   https://anonhg.NetBSD.org/src/rev/677e732d82f3
branches:  trunk
changeset: 827593:677e732d82f3
user:      cherry <cherry%NetBSD.org@localhost>
date:      Sat Nov 04 10:26:14 2017 +0000

description:
Add a PIC_XEN abstraction to evtchn.c

This allows us to get XEN interrupt code closer to unification to x86/intr.c

diffstat:

 sys/arch/x86/include/pic.h |    4 +-
 sys/arch/xen/xen/evtchn.c  |  169 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 170 insertions(+), 3 deletions(-)

diffs (217 lines):

diff -r 7735490d8fd5 -r 677e732d82f3 sys/arch/x86/include/pic.h
--- a/sys/arch/x86/include/pic.h        Sat Nov 04 09:31:08 2017 +0000
+++ b/sys/arch/x86/include/pic.h        Sat Nov 04 10:26:14 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pic.h,v 1.8 2015/04/27 07:03:58 knakahara Exp $        */
+/*     $NetBSD: pic.h,v 1.9 2017/11/04 10:26:14 cherry Exp $   */
 
 #ifndef _X86_PIC_H
 #define _X86_PIC_H
@@ -34,8 +34,10 @@
 #define PIC_MSI                3
 #define PIC_MSIX       4
 #define PIC_SOFT       5
+#define PIC_XEN                6
 
 extern struct pic i8259_pic;
 extern struct pic local_pic;
 extern struct pic softintr_pic;
+extern struct pic xen_pic;
 #endif
diff -r 7735490d8fd5 -r 677e732d82f3 sys/arch/xen/xen/evtchn.c
--- a/sys/arch/xen/xen/evtchn.c Sat Nov 04 09:31:08 2017 +0000
+++ b/sys/arch/xen/xen/evtchn.c Sat Nov 04 10:26:14 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: evtchn.c,v 1.73 2017/07/16 14:02:48 cherry Exp $       */
+/*     $NetBSD: evtchn.c,v 1.74 2017/11/04 10:26:14 cherry Exp $       */
 
 /*
  * Copyright (c) 2006 Manuel Bouyer.
@@ -54,7 +54,7 @@
 
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: evtchn.c,v 1.73 2017/07/16 14:02:48 cherry Exp $");
+__KERNEL_RCSID(0, "$NetBSD: evtchn.c,v 1.74 2017/11/04 10:26:14 cherry Exp $");
 
 #include "opt_xen.h"
 #include "isa.h"
@@ -115,6 +115,81 @@
 };
 #endif
 
+static void xen_evtchn_mask(struct pic *, int);
+static void xen_evtchn_unmask(struct pic *, int);
+static void xen_evtchn_addroute(struct pic *, struct cpu_info *, int, int, int);
+static void xen_evtchn_delroute(struct pic *, struct cpu_info *, int, int, int);
+static bool xen_evtchn_trymask(struct pic *, int);
+
+
+struct pic xen_pic = {
+       .pic_name = "xenev0",
+       .pic_type = PIC_XEN,
+       .pic_vecbase = 0,
+       .pic_apicid = 0,
+       .pic_lock = __SIMPLELOCK_UNLOCKED,
+       .pic_hwmask = xen_evtchn_mask,
+       .pic_hwunmask = xen_evtchn_unmask,
+       .pic_addroute = xen_evtchn_addroute,
+       .pic_delroute = xen_evtchn_delroute,
+       .pic_trymask = xen_evtchn_trymask,
+       .pic_level_stubs = xenev_stubs,
+       .pic_edge_stubs = xenev_stubs,
+};
+       
+/*
+ * We try to stick to the traditional x86 PIC semantics wrt Xen
+ * events.
+ *
+ * PIC pins exist in a global namespace which may be hierarchical, and
+ * are mapped to a cpu bus concept called 'IRQ' numbers, which are
+ * also global, but linear. Thus a PIC, pin tuple will always map to
+ * an IRQ number. These tuples can alias to the same IRQ number, thus
+ * causing IRQ "sharing". IRQ numbers can be bound to specific CPUs,
+ * and to specific callback vector indices on the CPU called idt_vec,
+ * which are aliases to handlers meant to run on destination
+ * CPUs. This binding can also happen at interrupt time and resolved
+ * 'round-robin' between all CPUs, depending on the lapic setup. In
+ * this case, all CPUs need to have identical idt_vec->handler
+ * mappings.
+ *
+ * The job of pic_addroute() is to setup the 'wiring' between the
+ * source pin, and the destination CPU handler, ideally on a specific
+ * CPU in MP systems (or 'round-robin').
+ *
+ * On Xen, a global namespace of 'events' exist, which are initially
+ * bound to nothing. This is similar to the relationship between
+ * realworld realworld IRQ numbers wrt PIC pins, since before routing,
+ * IRQ numbers by themselves have no causal connection setup with the
+ * real world. (Except for the hardwired cases on the PC Architecture,
+ * which we ignore for the purpose of this description). However the
+ * really important routing is from pin to idt_vec. On PIC_XEN, all
+ * three (pic, irq, idt_vec) belong to the same namespace and are
+ * identical. Further, the mapping between idt_vec and the actual
+ * callback handler is setup via calls to the evtchn.h api - this
+ * last bit is analogous to x86/idt.c:idt_vec_set() on real h/w
+ *
+ * For now we handle two cases:
+ * - IPC style events - eg: timer, PV devices, etc.
+ * - dom0 physical irq bound events.
+ *
+ * In the case of IPC style events, we currently externalise the
+ * event binding by using evtchn.h functions. From the POV of
+ * PIC_XEN ,  'pin' , 'irq' and 'idt_vec' are all identical to the
+ * port number of the event.
+ *
+ * In the case of dom0 physical irq bound events, we currently
+ * event binding by exporting evtchn.h functions. From the POV of
+ * PIC_LAPIC/PIC_IOAPIC, the 'pin' is the hardware pin, the 'irq' is
+ * the x86 global irq number  - the port number is extracted out of a
+ * global array (this is currently kludgy and breaks API abstraction)
+ * and the binding happens during pic_addroute() of the ioapic.
+ *
+ * Later when we integrate more tightly with x86/intr.c, we will be
+ * able to conform better to (PIC_LAPIC/PIC_IOAPIC)->PIC_XEN
+ * cascading model.
+ */
+
 int debug_port = -1;
 
 // #define IRQ_DEBUG 4
@@ -359,6 +434,96 @@
 
 #define PRIuCPUID      "lu" /* XXX: move this somewhere more appropriate */
 
+/* PIC callbacks */
+/* pic "pin"s are conceptually mapped to event port numbers */
+static void
+xen_evtchn_mask(struct pic *pic, int pin)
+{
+       evtchn_port_t evtchn = pin;
+
+       KASSERT(pic->pic_type == PIC_XEN);
+       KASSERT(evtchn < NR_EVENT_CHANNELS);
+
+       hypervisor_mask_event(evtchn);
+       
+}
+
+static void
+xen_evtchn_unmask(struct pic *pic, int pin)
+{
+       evtchn_port_t evtchn = pin;
+
+       KASSERT(pic->pic_type == PIC_XEN);
+       KASSERT(evtchn < NR_EVENT_CHANNELS);
+
+       hypervisor_unmask_event(evtchn);
+       
+}
+
+
+static void
+xen_evtchn_addroute(struct pic *pic, struct cpu_info *ci, int pin, int idt_vec, int type)
+{
+
+       evtchn_port_t evtchn = pin;
+
+       /* Events are simulated as level triggered interrupts */
+       KASSERT(type == IST_LEVEL); 
+
+       KASSERT(evtchn < NR_EVENT_CHANNELS);
+#if notyet
+       evtchn_port_t boundport = idt_vec;
+#endif
+       
+       KASSERT(pic->pic_type == PIC_XEN);
+
+       xen_atomic_set_bit(&ci->ci_evtmask[0], evtchn);
+
+}
+
+static void
+xen_evtchn_delroute(struct pic *pic, struct cpu_info *ci, int pin, int idt_vec, int type)
+{
+       /*
+        * XXX: In the future, this is a great place to
+        * 'unbind' events to underlying events and cpus.
+        * For now, just disable interrupt servicing on this cpu for
+        * this pin aka cpu.
+        */
+       evtchn_port_t evtchn = pin;
+
+       /* Events are simulated as level triggered interrupts */
+       KASSERT(type == IST_LEVEL); 
+
+       KASSERT(evtchn < NR_EVENT_CHANNELS);
+#if notyet
+       evtchn_port_t boundport = idt_vec;
+#endif
+       
+       KASSERT(pic->pic_type == PIC_XEN);
+
+       xen_atomic_clear_bit(&ci->ci_evtmask[0], evtchn);
+}
+
+static bool
+xen_evtchn_trymask(struct pic *pic, int pin)
+{
+       volatile shared_info_t *s = HYPERVISOR_shared_info;
+
+       /* Already masked! */
+       if (xen_atomic_test_bit(&s->evtchn_mask[0], pin))
+               return true;
+       
+       /* Pending - bail! */
+       if (xen_atomic_test_bit(&s->evtchn_pending[0], pin))
+               return false;
+
+       /* XXX: There's a race here - anything we can do about this ? */
+       /* Mask it */
+       xen_atomic_set_bit(&s->evtchn_mask[0], pin);
+       return true;
+}
+
 evtchn_port_t
 bind_vcpu_to_evtch(cpuid_t vcpu)
 {



Home | Main Index | Thread Index | Old Index