Port-xen archive

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

interrupt cleanup #1



Hello Xen,

I've been spending a little attention on our PV interrupt path with a
view to getting PVHVM etc. to work better.

Here's a first preview patch - it's just API reshuffling, but I'd be
grateful if people could test it both on domU and dom0.

The main change is that it now uses more of the x86/ common intr code
rather than modified copies that have bitrotted.

There should be no functional changes (the shutdown path is broken
though). 

I'm working on a second set of more intrusive patches. These will use
the SPL callpath to process the Xen PV racy interrupt scheduling. The
code works on domU, but not on dom0 due to separate issues that I'm
trying to debug. This patch is incremental in that direction.

Test, thoughts, feedback welcome.

-- 
~cherry

Index: arch/x86/include/intr.h
===================================================================
RCS file: /cvsroot/src/sys/arch/x86/include/intr.h,v
retrieving revision 1.51
diff -u -r1.51 intr.h
--- arch/x86/include/intr.h	16 Jul 2017 14:02:48 -0000	1.51
+++ arch/x86/include/intr.h	20 Oct 2017 00:47:12 -0000
@@ -124,11 +124,11 @@
 	void	*ih_realarg;
 	struct	intrhand *ih_next;
 	struct	intrhand **ih_prevp;
-#if !defined(XEN)
 	int	ih_pin;
 	int	ih_slot;
-#else
+#if defined(XEN)
 	struct	intrhand *ih_evt_next;
+	int pic_type;
 #endif
 	struct cpu_info *ih_cpu;
 };
Index: arch/x86/include/pic.h
===================================================================
RCS file: /cvsroot/src/sys/arch/x86/include/pic.h,v
retrieving revision 1.8
diff -u -r1.8 pic.h
--- arch/x86/include/pic.h	27 Apr 2015 07:03:58 -0000	1.8
+++ arch/x86/include/pic.h	20 Oct 2017 00:47:12 -0000
@@ -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
Index: arch/x86/isa/isa_machdep.c
===================================================================
RCS file: /cvsroot/src/sys/arch/x86/isa/isa_machdep.c,v
retrieving revision 1.36
diff -u -r1.36 isa_machdep.c
--- arch/x86/isa/isa_machdep.c	21 Jul 2017 12:27:48 -0000	1.36
+++ arch/x86/isa/isa_machdep.c	20 Oct 2017 00:47:35 -0000
@@ -245,7 +245,7 @@
 
 	mpih |= APIC_IRQ_LEGACY_IRQ(irq);
 
-	evtch = xen_intr_map((int *)&mpih, type); /* XXX: legacy - xen just tosses irq back at us */
+	evtch = xen_pirq_alloc((intr_handle_t *)&mpih, type); /* XXX: legacy - xen just tosses irq back at us */
 	if (evtch == -1)
 		return NULL;
 #if NIOAPIC > 0
Index: arch/x86/pci/pciide_machdep.c
===================================================================
RCS file: /cvsroot/src/sys/arch/x86/pci/pciide_machdep.c,v
retrieving revision 1.16
diff -u -r1.16 pciide_machdep.c
--- arch/x86/pci/pciide_machdep.c	15 Oct 2016 16:46:14 -0000	1.16
+++ arch/x86/pci/pciide_machdep.c	20 Oct 2017 00:47:36 -0000
@@ -61,6 +61,7 @@
 #include <machine/mpbiosvar.h>
 #endif
 
+#ifdef __HAVE_PCIIDE_MACHDEP_COMPAT_INTR_ESTABLISH
 void *
 pciide_machdep_compat_intr_establish(device_t dev,
     const struct pci_attach_args *pa, int chan, int (*func)(void *),
@@ -96,7 +97,9 @@
 	    PCIIDE_CHANNEL_NAME(chan), irq);
 	return cookie;
 }
+#endif /* __HAVE_PCIIDE_MACHDEP_COMPAT_INTR_ESTABLISH */
 
+#ifdef __HAVE_PCIIDE_MACHDEP_COMPAT_INTR_DISESTABLISH
 void
 pciide_machdep_compat_intr_disestablish(device_t dev, pci_chipset_tag_t pc,
     int chan, void *cookie)
@@ -104,3 +107,4 @@
 	isa_intr_disestablish(NULL, cookie);
 	return;
 }
+#endif /* __HAVE_PCIIDE_MACHDEP_COMPAT_INTR_DISESTABLISH */
Index: arch/x86/x86/idt.c
===================================================================
RCS file: /cvsroot/src/sys/arch/x86/x86/idt.c,v
retrieving revision 1.5
diff -u -r1.5 idt.c
--- arch/x86/x86/idt.c	7 Aug 2017 17:10:09 -0000	1.5
+++ arch/x86/x86/idt.c	20 Oct 2017 00:47:37 -0000
@@ -75,9 +75,12 @@
 
 #include <machine/segments.h>
 
+/* On xen PV this is just numberspace management - used in x86/intr.c */
 #if !defined(XEN)
 
 struct gate_descriptor *idt;
+#endif
+
 static char idt_allocmap[NIDT];
 
 /*
@@ -120,8 +123,10 @@
 {
 
 	KASSERT(idt_allocmap[vec] == 1);
+#if !defined(XEN)
 	setgate(&idt[vec], function, 0, SDT_SYS386IGT, SEL_KPL,
 	    GSEL(GCODE_SEL, SEL_KPL));
+#endif
 }
 
 /*
@@ -131,8 +136,9 @@
 idt_vec_free(int vec)
 {
 
+#if !defined(XEN)
 	unsetgate(&idt[vec]);
+#endif
 	idt_allocmap[vec] = 0;
 }
 
-#endif /* !defined(XEN) */
Index: arch/x86/x86/ioapic.c
===================================================================
RCS file: /cvsroot/src/sys/arch/x86/x86/ioapic.c,v
retrieving revision 1.52
diff -u -r1.52 ioapic.c
--- arch/x86/x86/ioapic.c	27 Jul 2015 15:45:20 -0000	1.52
+++ arch/x86/x86/ioapic.c	20 Oct 2017 00:47:38 -0000
@@ -565,6 +565,25 @@
 	pp->ip_vector = idtvec;
 	pp->ip_cpu = ci;
 	apic_set_redir(sc, pin, idtvec, ci);
+
+#if defined(XEN)
+	/*
+	 * This is kludgy, and not the right place, but we can't bind
+	 * before the routing has been set to the appropriate 'vector'.
+	 * in x86/intr.c, this is done after idt_vec_set(), where this
+	 * would have been more appropriate to put this.
+	 */
+
+	int port, irq;
+	irq = vect2irq[idtvec];
+	port = bind_pirq_to_evtch(irq);
+	KASSERT(port < NR_EVENT_CHANNELS);
+
+	irq2port[irq] = port;
+	
+	xen_atomic_set_bit(&ci->ci_evtmask[0], port);
+#endif
+	
 }
 
 static void
@@ -573,6 +592,16 @@
 {
 
 	ioapic_hwmask(pic, pin);
+
+#if defined(XEN)
+	int port, irq;
+	irq = vect2irq[idtvec];
+	port = bind_pirq_to_evtch(irq);
+	port = unbind_pirq_from_evtch(irq);
+
+	KASSERT(port < NR_EVENT_CHANNELS);
+#endif
+	
 }
 
 #ifdef DDB
Index: arch/xen/conf/files.xen
===================================================================
RCS file: /cvsroot/src/sys/arch/xen/conf/files.xen,v
retrieving revision 1.153
diff -u -r1.153 files.xen
--- arch/xen/conf/files.xen	9 Aug 2017 18:48:53 -0000	1.153
+++ arch/xen/conf/files.xen	20 Oct 2017 00:47:49 -0000
@@ -137,4 +137,5 @@
 file	arch/xen/x86/consinit.c		machdep
 file	arch/x86/x86/identcpu.c		machdep
 file	arch/xen/x86/intr.c		machdep
+file	arch/xen/x86/pintr.c		machdep & dom0ops
 file	arch/xen/x86/xen_ipi.c		multiprocessor
@@ -231,7 +233,7 @@
 include "dev/i2o/files.i2o"
 include "dev/pci/files.pci"
 include "dev/pci/files.agp"
-file	arch/xen/xen/pciide_machdep.c	pciide_common
+file	arch/x86/pci/pciide_machdep.c	pciide_common
 
 device	pciback {unit = -1}
 attach	pciback at pci
@@ -383,7 +385,9 @@
 file	arch/xen/xen/privcmd.c		dom0ops
 file 	arch/xen/x86/xen_shm_machdep.c	dom0ops
 file	arch/x86/pci/pci_machdep.c	hypervisor & pci & dom0ops
-file	arch/xen/xen/pci_intr_machdep.c	hypervisor & pci
+file	arch/x86/pci/pci_intr_machdep.c	hypervisor & pci
+file	arch/x86/pci/pci_msi_machdep.c	hypervisor & pci
+file	arch/x86/pci/msipic.c		hypervisor & pci
 file	arch/x86/isa/isa_machdep.c	hypervisor & dom0ops
 file	arch/xen/xen/xenevt.c		xenevt & dom0ops
 file	arch/xen/xen/xennetback_xenbus.c xvif
Index: arch/xen/include/evtchn.h
===================================================================
RCS file: /cvsroot/src/sys/arch/xen/include/evtchn.h,v
retrieving revision 1.24
diff -u -r1.24 evtchn.h
--- arch/xen/include/evtchn.h	16 Jul 2017 05:03:36 -0000	1.24
+++ arch/xen/include/evtchn.h	20 Oct 2017 00:47:49 -0000
@@ -44,6 +44,9 @@
 int event_set_handler(int, int (*func)(void *), void *, int, const char *);
 int event_remove_handler(int, int (*func)(void *), void *);
 
+void xen_channel_free(evtchn_port_t);
+void xen_channel_set(evtchn_port_t, void *, int, int);
+
 struct cpu_info;
 struct intrhand;
 void event_set_iplhandler(struct cpu_info *, struct intrhand *, int);
@@ -64,6 +67,7 @@
 	int evtch;
 	int (*func)(void *);
 	void *arg;
+	int pic_type;
 };
 
 struct pintrhand *pirq_establish(int, int, int (*)(void *), void *, int,
Index: arch/xen/include/intr.h
===================================================================
RCS file: /cvsroot/src/sys/arch/xen/include/intr.h,v
retrieving revision 1.42
diff -u -r1.42 intr.h
--- arch/xen/include/intr.h	16 Jul 2017 14:02:48 -0000	1.42
+++ arch/xen/include/intr.h	20 Oct 2017 00:47:49 -0000
@@ -58,18 +58,21 @@
 	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 */
+	void (*ist_entry);		/* stub handler for this channel */
+	int slot;			/* Slot corresponding to entry */
+	int level;			/* IPL_XXX interrupt priority  */
 };
 
 extern struct intrstub xenev_stubs[];
-
+extern int irq2vect[256];
+extern int vect2irq[256];
+extern int irq2port[NR_EVENT_CHANNELS];
 
 #ifdef MULTIPROCESSOR
 int xen_intr_biglock_wrapper(void *);
 #endif
 
-int xen_intr_map(int *, int);
-struct pic *intr_findpic(int);
-void intr_add_pcibus(struct pcibus_attach_args *);
+int xen_pirq_alloc(intr_handle_t *, int);
 
 #ifdef MULTIPROCESSOR
 void xen_ipi_init(void);
Index: arch/xen/x86/intr.c
===================================================================
RCS file: /cvsroot/src/sys/arch/xen/x86/intr.c,v
retrieving revision 1.32
diff -u -r1.32 intr.c
--- arch/xen/x86/intr.c	16 Jul 2017 06:14:24 -0000	1.32
+++ arch/xen/x86/intr.c	20 Oct 2017 00:47:50 -0000
@@ -113,6 +113,7 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/kmem.h>
 #include <sys/syslog.h>
 #include <sys/device.h>
 #include <sys/malloc.h>
@@ -140,6 +141,7 @@
 struct intrstub x2apic_level_stubs[MAX_INTR_SOURCES] = {{0,0}};
 
 #include <machine/i82093var.h>
+int irq2port[NR_EVENT_CHANNELS] = {0};
 int irq2vect[256] = {0};
 int vect2irq[256] = {0};
 #endif /* NIOAPIC */
@@ -155,6 +157,44 @@
 #include <dev/pci/ppbreg.h>
 #endif
 
+const char * /* XXX: transitional - will axe this for x86/intr.c */
+intr_string(intr_handle_t ih, char *buf, size_t len)
+{
+#if NIOAPIC > 0
+	struct ioapic_softc *pic;
+#endif
+
+	if (ih == 0)
+		panic("%s: bogus handle 0x%" PRIx64, __func__, ih);
+
+#if NIOAPIC > 0
+	if (ih & APIC_INT_VIA_APIC) {
+		pic = ioapic_find(APIC_IRQ_APIC(ih));
+		if (pic != NULL) {
+			snprintf(buf, len, "%s pin %d",
+			    device_xname(pic->sc_dev), APIC_IRQ_PIN(ih));
+		} else {
+			snprintf(buf, len,
+			    "apic %d int %d (irq %d)",
+			    APIC_IRQ_APIC(ih),
+			    APIC_IRQ_PIN(ih),
+			    APIC_IRQ_LEGACY_IRQ(ih));
+		}
+	} else
+		snprintf(buf, len, "irq %d", APIC_IRQ_LEGACY_IRQ(ih));
+#else
+
+	snprintf(buf, len, "irq %d" APIC_IRQ_LEGACY_IRQ(ih));
+#endif
+	return buf;
+
+}
+
+void
+intr_free_io_intrsource(const char *intrid)
+{
+	/* XXX: Transitional - will axe for x86/intr.c */
+}
 /*
  * Fake interrupt handler structures for the benefit of symmetry with
  * other interrupt sources.
@@ -207,6 +247,26 @@
 	struct pintrhand *ih;
 	int evtchn;
 	char evname[16];
+
+	if (pic->pic_type == PIC_XEN) {
+		struct intrhand *rih;
+		event_set_handler(pin, handler,
+		    arg, IPL_CLOCK, "clock");
+
+		rih = kmem_zalloc(sizeof(struct intrhand),
+	    cold ? KM_NOSLEEP : KM_SLEEP);
+		if (rih == NULL) {
+			printf("%s: can't allocate handler info\n", __func__);
+			return NULL;
+		}
+
+		rih->ih_pin = pin; /* port */
+		rih->ih_fun = handler;
+		rih->ih_arg = arg;
+		rih->pic_type = pic->pic_type;
+		return rih;
+	} 	/* Else we assume pintr */
+
 #ifdef DIAGNOSTIC
 	if (legacy_irq != -1 && (legacy_irq < 0 || legacy_irq > 15))
 		panic("intr_establish: bad legacy IRQ value");
@@ -227,64 +287,12 @@
 	} else
 		snprintf(evname, sizeof(evname), "irq%d", legacy_irq);
 
-	evtchn = xen_intr_map(&legacy_irq, type);
+	evtchn = xen_pirq_alloc((intr_handle_t *)&legacy_irq, type);
 	ih = pirq_establish(legacy_irq & 0xff, evtchn, handler, arg, level,
 	    evname);
 	return ih;
 }
 
-int
-xen_intr_map(int *pirq, int type)
-{
-	int irq = *pirq;
-#if NIOAPIC > 0
-	extern struct cpu_info phycpu_info_primary; /* XXX */
-	/*
-	 * The hypervisor has already allocated vectors and IRQs for the
-	 * devices. Reusing the same IRQ doesn't work because as we bind
-	 * them for each devices, we can't then change the route entry
-	 * of the next device if this one used this IRQ. The easiest is
-	 * to allocate IRQs top-down, starting with a high number.
-	 * 250 and 230 have been tried, but got rejected by Xen.
-	 *
-	 * Xen 3.5 also rejects 200. Try out all values until Xen accepts
-	 * or none is available.
-	 */
-	static int xen_next_irq = 200;
-	struct ioapic_softc *ioapic = ioapic_find(APIC_IRQ_APIC(*pirq));
-	struct pic *pic = &ioapic->sc_pic;
-	int pin = APIC_IRQ_PIN(*pirq);
-	physdev_op_t op;
-
-	if (*pirq & APIC_INT_VIA_APIC) {
-		irq = vect2irq[ioapic->sc_pins[pin].ip_vector];
-		if (ioapic->sc_pins[pin].ip_vector == 0 || irq == 0) {
-			/* allocate IRQ */
-			irq = APIC_IRQ_LEGACY_IRQ(*pirq);
-			if (irq <= 0 || irq > 15)
-				irq = xen_next_irq--;
-retry:
-			/* allocate vector and route interrupt */
-			op.cmd = PHYSDEVOP_ASSIGN_VECTOR;
-			op.u.irq_op.irq = irq;
-			if (HYPERVISOR_physdev_op(&op) < 0) {
-				irq = xen_next_irq--;
-				if (xen_next_irq == 15)
-					panic("PHYSDEVOP_ASSIGN_VECTOR irq %d", irq);
-				goto retry;
-			}
-			irq2vect[irq] = op.u.irq_op.vector;
-			vect2irq[op.u.irq_op.vector] = irq;
-			pic->pic_addroute(pic, &phycpu_info_primary, pin,
-			    op.u.irq_op.vector, type);
-		}
-		*pirq &= ~0xff;
-		*pirq |= irq;
-	}
-#endif /* NIOAPIC */
-	return bind_pirq_to_evtch(irq);
-}
-
 void
 intr_disestablish(struct intrhand *ih)
 {
Index: arch/xen/x86/xen_ipi.c
===================================================================
RCS file: /cvsroot/src/sys/arch/xen/x86/xen_ipi.c,v
retrieving revision 1.20
diff -u -r1.20 xen_ipi.c
--- arch/xen/x86/xen_ipi.c	7 Jul 2016 06:55:40 -0000	1.20
+++ arch/xen/x86/xen_ipi.c	20 Oct 2017 00:47:50 -0000
@@ -82,12 +82,17 @@
 	xen_ipi_generic,
 };
 
-static void
-xen_ipi_handler(struct cpu_info *ci, struct intrframe *regs)
+static int
+xen_ipi_handler(void *arg)
 {
 	uint32_t pending;
 	int bit;
+	struct cpu_info *ci;
+	struct intrframe *regs;
 
+	ci = curcpu();
+	regs = arg;
+	
 	pending = atomic_swap_32(&ci->ci_ipis, 0);
 
 	KDASSERT((pending >> XEN_NIPIS) == 0);
@@ -102,6 +107,8 @@
 			/* NOTREACHED */
 		}
 	}
+
+	return 0;
 }
 
 /* Must be called once for every cpu that expects to send/recv ipis */
@@ -122,9 +129,9 @@
 
 	KASSERT(evtchn != -1 && evtchn < NR_EVENT_CHANNELS);
 
-	if (0 != event_set_handler(evtchn, (int (*)(void *))xen_ipi_handler,
-				   ci, IPL_HIGH, "ipi")) {
-		panic("event_set_handler(...) KPI violation\n");
+	if(intr_establish_xname(0, &xen_pic, evtchn, IST_LEVEL, IPL_HIGH,
+		xen_ipi_handler, ci, true, "ipi") == NULL) {
+		panic("%s: unable to register ipi handler\n", __func__);
 		/* NOTREACHED */
 	}
 
Index: arch/xen/xen/clock.c
===================================================================
RCS file: /cvsroot/src/sys/arch/xen/xen/clock.c,v
retrieving revision 1.64
diff -u -r1.64 clock.c
--- arch/xen/xen/clock.c	12 Jun 2016 09:08:09 -0000	1.64
+++ arch/xen/xen/clock.c	20 Oct 2017 00:47:50 -0000
@@ -49,7 +49,8 @@
 #include <dev/clock_subr.h>
 #include <x86/rtc.h>
 
-static int xen_timer_handler(void *, struct intrframe *);
+static int xen_timer_handler(void *);
+static struct intrhand *ih;
 
 /* A timecounter: Xen system_time extrapolated with a TSC. */
 u_int xen_get_timecount(struct timecounter*);
@@ -509,7 +510,7 @@
 	KASSERT(evtch != -1);
 
 	hypervisor_mask_event(evtch);
-	event_remove_handler(evtch, (int (*)(void *))xen_timer_handler, ci);
+	intr_disestablish(ih);
 
 	aprint_verbose("Xen clock: removed event channel %d\n", evtch);
 }
@@ -522,8 +523,11 @@
 	evtch = bind_virq_to_evtch(VIRQ_TIMER);
 	KASSERT(evtch != -1);
 
-	event_set_handler(evtch, (int (*)(void *))xen_timer_handler,
-	    ci, IPL_CLOCK, "clock");
+	ih = intr_establish_xname(0, &xen_pic, evtch, IST_LEVEL, IPL_CLOCK,
+	    xen_timer_handler, ci, true, "clock");
+
+	KASSERT(ih != NULL);
+
 	hypervisor_enable_event(evtch);
 
 	aprint_verbose("Xen clock: using event channel %d\n", evtch);
@@ -531,11 +535,12 @@
 
 /* ARGSUSED */
 static int
-xen_timer_handler(void *arg, struct intrframe *regs)
+xen_timer_handler(void *arg)
 {
 	int64_t delta;
 	struct cpu_info *ci = curcpu();
-	KASSERT(arg == ci);
+	struct intrframe *regs = arg;
+
 	int err;
 again:
 	mutex_enter(&tmutex);
Index: arch/xen/xen/evtchn.c
===================================================================
RCS file: /cvsroot/src/sys/arch/xen/xen/evtchn.c,v
retrieving revision 1.73
diff -u -r1.73 evtchn.c
--- arch/xen/xen/evtchn.c	16 Jul 2017 14:02:48 -0000	1.73
+++ arch/xen/xen/evtchn.c	20 Oct 2017 00:47:51 -0000
@@ -115,6 +115,87 @@
 };
 #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 setup. In this
+ * case, all CPUs need to have identical idt_vec->handler mappings.
+ *
+ * The job of pic_addroute() is to setup this '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).
+ *
+ * To be useful, events are bound to underlying real world events like
+ * IRQ lines, interdomain RPCs, "Virtual IRQ requests (eg: timer) or
+ * Inter Processor Interrupts. However, unlike PIC pins, the above set
+ * of namespaces are collisive and not mutually exclusive. This means
+ * that they need to be expressed as a tuple, indicating the
+ * namespace. There are two ways to do this - the first is to consider
+ * each namespace as a separate 'slave' PIC which maps pins to global
+ * 'IRQ's. Each slave PIC is then connected to a master PIC which does
+ * the final routing to the global event number.
+ * Thus the tuple will contain the pic handle and the pin
+ * number, for eg: pic_type == PIC_XEN_VIRQ, pin == VIRQ_TIMER, ...
+ * 
+ * I felt that this scheme is unnecessarily complicated, especially
+ * since the handler code and EOI protocol for Xen events are all
+ * identical irrespective of the underlying source.
+ * I thus decided to map the namespace separation idea onto the
+ * interrupt "type" on a single virtual PIC.
+ * Thus we have:
+ * pic_type == PIC_XEN, type == IST_XEN_VIRQ, pin == VIRQ_TIMER, ...
+ * 
+ * The job of pic_addroute() therefore is to make the causal
+ * connection between realworld events and an actual vcpu handler.
+ *
+ * In order to do this, we make the following conceptual mappings
+ * between real PICs and our imaginary one:
+ *
+ * pin => "real world event" (eg: VIRQ, PIRQ, IPI).
+ * type => IST_$NAMESPACE (eg: IST_VIRQ, IST_PIRQ, IST_IPI)
+ * IRQ => event number
+ * idt_vec => Constant. On PVHVM, this is a fixed per-VCPU vector.
+ *
+ */
+
 int debug_port = -1;
 
 // #define IRQ_DEBUG 4
@@ -359,6 +440,123 @@
 
 #define PRIuCPUID	"lu" /* XXX: move this somewhere more appropriate */
 
+void
+xen_channel_free(evtchn_port_t evtchn)
+{
+	KASSERT((evtchn > 0) && (evtchn < NR_EVENT_CHANNELS));
+	
+	mutex_spin_enter(&evtchn_lock);
+	evtsource[evtchn]->ist_entry = NULL; /* XXX: confirm invalid */
+	evtsource[evtchn]->slot = -1;
+	mutex_spin_exit(&evtchn_lock);
+}
+
+void
+xen_channel_set(evtchn_port_t evtchn, void *stub, int slot, int level)
+{
+	KASSERT((evtchn > 0) && (evtchn < NR_EVENT_CHANNELS));
+	KASSERT(stub != NULL);
+	
+	mutex_spin_enter(&evtchn_lock);
+	/* XXX: reset the corresponding evtmask */
+	evtsource[evtchn]->ist_entry = stub; /* XXX: confirm invalid */
+	evtsource[evtchn]->slot = slot;
+	evtsource[evtchn]->level = level;
+	mutex_spin_exit(&evtchn_lock);
+}
+
+/* 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;
+	
+#if notyet // XXX: Whole thing needs review. mask and pending don't sync
+	/* 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 ? */
+#endif
+	/* Mask it */
+	xen_atomic_set_bit(&s->evtchn_mask[0], pin);
+	return true;
+}
+
 evtchn_port_t
 bind_vcpu_to_evtch(cpuid_t vcpu)
 {
Index: arch/xen/xen/if_xennet_xenbus.c
===================================================================
RCS file: /cvsroot/src/sys/arch/xen/xen/if_xennet_xenbus.c,v
retrieving revision 1.70
diff -u -r1.70 if_xennet_xenbus.c
--- arch/xen/xen/if_xennet_xenbus.c	4 Mar 2017 19:11:01 -0000	1.70
+++ arch/xen/xen/if_xennet_xenbus.c	20 Oct 2017 00:47:51 -0000
@@ -180,7 +180,8 @@
 
 	unsigned int sc_evtchn;
 	void *sc_softintr;
-
+	struct intrhand *sc_ih;
+	
 	grant_ref_t sc_tx_ring_gntref;
 	grant_ref_t sc_rx_ring_gntref;
 
@@ -422,7 +423,7 @@
 	DPRINTF(("%s: xennet_xenbus_detach\n", device_xname(self)));
 	s0 = splnet();
 	xennet_stop(ifp, 1);
-	event_remove_handler(sc->sc_evtchn, &xennet_handler, sc);
+	intr_disestablish(sc->sc_ih);
 	/* wait for pending TX to complete, and collect pending RX packets */
 	xennet_handler(sc);
 	while (sc->sc_tx_ring.sring->rsp_prod != sc->sc_tx_ring.rsp_cons) {
@@ -513,8 +514,9 @@
 		goto abort_resume;
 	aprint_verbose_dev(dev, "using event channel %d\n",
 	    sc->sc_evtchn);
-	event_set_handler(sc->sc_evtchn, &xennet_handler, sc,
-	    IPL_NET, device_xname(dev));
+	sc->sc_ih = intr_establish_xname(0, &xen_pic, sc->sc_evtchn, IST_LEVEL, IPL_NET,
+	    &xennet_handler, sc, true, device_xname(dev));
+	KASSERT(sc->sc_ih != NULL);
 	return true;
 
 abort_resume:
@@ -635,7 +637,7 @@
 	 */
 
 	sc->sc_backend_status = BEST_SUSPENDED;
-	event_remove_handler(sc->sc_evtchn, &xennet_handler, sc);
+	intr_disestablish(sc->sc_ih);
 
 	splx(s);
 
Index: arch/xen/xen/xbd_xenbus.c
===================================================================
RCS file: /cvsroot/src/sys/arch/xen/xen/xbd_xenbus.c,v
retrieving revision 1.76
diff -u -r1.76 xbd_xenbus.c
--- arch/xen/xen/xbd_xenbus.c	5 Mar 2017 23:07:12 -0000	1.76
+++ arch/xen/xen/xbd_xenbus.c	20 Oct 2017 00:47:51 -0000
@@ -123,6 +123,8 @@
 	struct dk_softc sc_dksc;	/* Must be first in this struct */
 	struct xenbus_device *sc_xbusd;
 
+	struct intrhand *sc_ih; /* Interrupt handler for this instance. */
+	
 	blkif_front_ring_t sc_ring;
 
 	unsigned int sc_evtchn;
@@ -368,7 +370,8 @@
 	}
 
 	hypervisor_mask_event(sc->sc_evtchn);
-	event_remove_handler(sc->sc_evtchn, &xbd_handler, sc);
+	intr_disestablish(sc->sc_ih);
+
 	while (xengnt_status(sc->sc_ring_gntref)) {
 		tsleep(xbd_xenbus_detach, PRIBIO, "xbd_ref", hz/2);
 	}
@@ -397,7 +400,7 @@
 
 	hypervisor_mask_event(sc->sc_evtchn);
 	sc->sc_backend_status = BLKIF_STATE_SUSPENDED;
-	event_remove_handler(sc->sc_evtchn, xbd_handler, sc);
+	intr_disestablish(sc->sc_ih);
 
 	splx(s);
 
@@ -449,8 +452,9 @@
 
 	aprint_verbose_dev(dev, "using event channel %d\n",
 	    sc->sc_evtchn);
-	event_set_handler(sc->sc_evtchn, &xbd_handler, sc,
-	    IPL_BIO, device_xname(dev));
+	sc->sc_ih = intr_establish_xname(0, &xen_pic, sc->sc_evtchn, IST_LEVEL, IPL_BIO, &xbd_handler, sc, true, "clock");
+	
+	KASSERT(sc->sc_ih != NULL);
 
 again:
 	xbt = xenbus_transaction_start();
Index: arch/xen/xen/xbdback_xenbus.c
===================================================================
RCS file: /cvsroot/src/sys/arch/xen/xen/xbdback_xenbus.c,v
retrieving revision 1.63
diff -u -r1.63 xbdback_xenbus.c
--- arch/xen/xen/xbdback_xenbus.c	26 Dec 2016 08:16:28 -0000	1.63
+++ arch/xen/xen/xbdback_xenbus.c	20 Oct 2017 00:47:52 -0000
@@ -170,6 +170,7 @@
 	bool xbdi_ro; /* is device read-only ? */
 	/* parameters for the communication */
 	unsigned int xbdi_evtchn;
+	struct intrhand *xbdi_ih;
 	/* private parameters for communication */
 	blkif_back_ring_proto_t xbdi_ring;
 	enum xbdi_proto xbdi_proto;
@@ -636,8 +637,9 @@
 	XENPRINTF(("xbdback %s: connect evchannel %d\n", xbusd->xbusd_path, xbdi->xbdi_evtchn));
 	xbdi->xbdi_evtchn = evop.u.bind_interdomain.local_port;
 
-	event_set_handler(xbdi->xbdi_evtchn, xbdback_evthandler,
-	    xbdi, IPL_BIO, xbdi->xbdi_name);
+	xbdi->xbdi_ih = intr_establish_xname(0, &xen_pic, xbdi->xbdi_evtchn, IST_LEVEL, IPL_BIO,
+	    xbdback_evthandler, xbdi, true, xbdi->xbdi_name);
+	KASSERT(xbdi->xbdi_ih != NULL);
 	aprint_verbose("xbd backend domain %d handle %#x (%d) "
 	    "using event channel %d, protocol %s\n", xbdi->xbdi_domid,
 	    xbdi->xbdi_handle, xbdi->xbdi_handle, xbdi->xbdi_evtchn, proto);
@@ -681,8 +683,7 @@
 		return;
 	}
 	hypervisor_mask_event(xbdi->xbdi_evtchn);
-	event_remove_handler(xbdi->xbdi_evtchn, xbdback_evthandler,
-	    xbdi);
+	intr_disestablish(xbdi->xbdi_ih);
 
 	/* signal thread that we want to disconnect, then wait for it */
 	xbdi->xbdi_status = DISCONNECTING;
Index: arch/xen/xen/xencons.c
===================================================================
RCS file: /cvsroot/src/sys/arch/xen/xen/xencons.c,v
retrieving revision 1.41
diff -u -r1.41 xencons.c
--- arch/xen/xen/xencons.c	25 Jul 2014 08:10:35 -0000	1.41
+++ arch/xen/xen/xencons.c	20 Oct 2017 00:47:52 -0000
@@ -90,6 +90,7 @@
 
 static int xencons_isconsole = 0;
 static struct xencons_softc *xencons_console_device = NULL;
+static struct intrhand *ih;
 
 #define	XENCONS_UNIT(x)	(minor(x))
 #define XENCONS_BURST 128
@@ -216,13 +217,8 @@
 	if (!xendomain_is_dom0()) {
 		evtch = xen_start_info.console_evtchn;
 		hypervisor_mask_event(evtch);
-		if (event_remove_handler(evtch, xencons_handler,
-		    xencons_console_device) != 0) {
-			aprint_error_dev(dev,
-			    "can't remove handler: xencons_handler\n");
-		}
-
-		aprint_verbose_dev(dev, "removed event channel %d\n", evtch);
+		intr_disestablish(ih);
+		aprint_verbose_dev(dev, "removed event channel %d\n", ih->ih_pin);
 	}
 
 	return true;
@@ -237,13 +233,15 @@
 	/* dom0 console resume is required only during first start-up */
 		if (cold) {
 			evtch = bind_virq_to_evtch(VIRQ_CONSOLE);
-			event_set_handler(evtch, xencons_intr,
-			    xencons_console_device, IPL_TTY, "xencons");
+			ih = intr_establish_xname(0, &xen_pic, evtch, IST_LEVEL, IPL_TTY,
+			    xencons_intr, xencons_console_device, true, "xencons");
+			KASSERT(ih != NULL);
 		}
 	} else {
 		evtch = xen_start_info.console_evtchn;
-		event_set_handler(evtch, xencons_handler,
-		    xencons_console_device, IPL_TTY, "xencons");
+		ih = intr_establish_xname(0, &xen_pic, evtch, IST_LEVEL, IPL_TTY,
+		    xencons_handler, xencons_console_device, true, "xencons");
+		KASSERT(ih != NULL);
 	}
 
 	if (evtch != -1) {
Index: arch/xen/xen/xennetback_xenbus.c
===================================================================
RCS file: /cvsroot/src/sys/arch/xen/xen/xennetback_xenbus.c,v
retrieving revision 1.58
diff -u -r1.58 xennetback_xenbus.c
--- arch/xen/xen/xennetback_xenbus.c	15 Dec 2016 09:28:04 -0000	1.58
+++ arch/xen/xen/xennetback_xenbus.c	20 Oct 2017 00:47:53 -0000
@@ -112,7 +112,8 @@
 	uint8_t xni_enaddr[ETHER_ADDR_LEN];
 
 	/* remote domain communication stuff */
-	unsigned int xni_evtchn; /* our even channel */
+	unsigned int xni_evtchn; /* our event channel */
+	struct intrhand *xni_ih;
 	netif_tx_back_ring_t xni_txring;
 	netif_rx_back_ring_t xni_rxring;
 	grant_handle_t xni_tx_ring_handle; /* to unmap the ring */
@@ -389,7 +390,8 @@
 #endif
 	aprint_verbose_ifnet(&xneti->xni_if, "disconnecting\n");
 	hypervisor_mask_event(xneti->xni_evtchn);
-	event_remove_handler(xneti->xni_evtchn, xennetback_evthandler, xneti);
+	intr_disestablish(xneti->xni_ih);
+
 	if (xneti->xni_softintr) {
 		softint_disestablish(xneti->xni_softintr);
 		xneti->xni_softintr = NULL;
@@ -549,8 +551,9 @@
 	xneti->xni_status = CONNECTED;
 	xen_wmb();
 
-	event_set_handler(xneti->xni_evtchn, xennetback_evthandler,
-	    xneti, IPL_NET, xneti->xni_if.if_xname);
+	xneti->xni_ih = intr_establish_xname(0, &xen_pic, xneti->xni_evtchn, IST_LEVEL, IPL_NET,
+	    xennetback_evthandler, xneti, true, xneti->xni_if.if_xname);
+	KASSERT(xneti->xni_ih != NULL);
 	xennetback_ifinit(&xneti->xni_if);
 	hypervisor_enable_event(xneti->xni_evtchn);
 	hypervisor_notify_via_evtchn(xneti->xni_evtchn);
Index: arch/xen/xenbus/xenbus_comms.c
===================================================================
RCS file: /cvsroot/src/sys/arch/xen/xenbus/xenbus_comms.c,v
retrieving revision 1.15
diff -u -r1.15 xenbus_comms.c
--- arch/xen/xenbus/xenbus_comms.c	7 Jul 2016 06:55:40 -0000	1.15
+++ arch/xen/xenbus/xenbus_comms.c	20 Oct 2017 00:47:53 -0000
@@ -40,6 +40,7 @@
 
 #include <xen/xen.h>	/* for xendomain_is_dom0() */
 #include <xen/hypervisor.h>
+#include <xen/pic.h>
 #include <xen/evtchn.h>
 #include <xen/xenbus.h>
 #include "xenbus_comms.h"
@@ -51,6 +52,7 @@
 #define XENPRINTF(x)
 #endif
 
+static struct intrhand *ih;
 struct xenstore_domain_interface *xenstore_interface;
 
 extern int xenstored_ready;
@@ -220,7 +222,9 @@
 
 	evtchn = xen_start_info.store_evtchn;
 
-	event_set_handler(evtchn, wake_waiting, NULL, IPL_TTY, "xenbus");
+	ih = intr_establish_xname(0, &xen_pic, evtchn, IST_LEVEL, IPL_TTY,
+	    wake_waiting, NULL, true, "xenbus");
+
 	hypervisor_enable_event(evtchn);
 	aprint_verbose_dev(dev, "using event channel %d\n", evtchn);
 
@@ -235,7 +239,7 @@
 	evtchn = xen_start_info.store_evtchn;
 
 	hypervisor_mask_event(evtchn);
-	event_remove_handler(evtchn, wake_waiting, NULL);
+	intr_disestablish(ih);
 	aprint_verbose_dev(dev, "removed event channel %d\n", evtchn);
 }
 
Index: arch/xen/x86/pintr.c
===================================================================
RCS file: arch/xen/x86/pintr.c
diff -N arch/xen/x86/pintr.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ arch/xen/x86/pintr.c	20 Oct 2017 09:36:39 -0000
@@ -0,0 +1,208 @@
+/*	NetBSD: intr.c,v 1.15 2004/04/10 14:49:55 kochi Exp 	*/
+
+/*
+ * Copyright 2002 (c) Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Frank van der Linden for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed for the NetBSD Project by
+ *      Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ *    or promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)isa.c       7.2 (Berkeley) 5/13/91
+ */
+/*-
+ * Copyright (c) 1993, 1994 Charles Hannum.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)isa.c       7.2 (Berkeley) 5/13/91
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.32 2017/07/16 06:14:24 cherry Exp $");
+
+#include "opt_multiprocessor.h"
+#include "opt_xen.h"
+#include "isa.h"
+#include "pci.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/errno.h>
+#include <sys/cpu.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/i8259.h>
+#include <machine/pio.h>
+#include <xen/evtchn.h>
+#include <xen/intr.h>
+
+#include "acpica.h"
+#include "ioapic.h"
+#include "opt_mpbios.h"
+
+#if NIOAPIC > 0
+/* XXX: todo - compat with lapic.c and XEN for x2apic */
+bool x2apic_mode __read_mostly = false;
+/* for x86/ioapic.c */
+//struct intrstub ioapic_edge_stubs[MAX_INTR_SOURCES] = {{0,0,0}};
+//struct intrstub ioapic_level_stubs[MAX_INTR_SOURCES] = {{0,0,0}};
+//struct intrstub x2apic_edge_stubs[MAX_INTR_SOURCES] = {{0,0,0}};
+//struct intrstub x2apic_level_stubs[MAX_INTR_SOURCES] = {{0,0,0}};
+#include <machine/i82093var.h>
+//int irq2vect[256] = {0};
+//int vect2irq[256] = {0};
+#endif /* NIOAPIC */
+#if NACPICA > 0
+#include <machine/mpconfig.h>
+#include <machine/mpacpi.h>
+#endif
+#ifdef MPBIOS
+#include <machine/mpbiosvar.h>
+#endif
+
+#if NPCI > 0
+#include <dev/pci/ppbreg.h>
+#endif
+
+int
+xen_pirq_alloc(intr_handle_t *pirq, int type)
+{
+	int irq = *pirq;
+#if NIOAPIC > 0
+	extern struct cpu_info phycpu_info_primary; /* XXX */
+	/*
+	 * The hypervisor has already allocated vectors and IRQs for the
+	 * devices. Reusing the same IRQ doesn't work because as we bind
+	 * them for each devices, we can't then change the route entry
+	 * of the next device if this one used this IRQ. The easiest is
+	 * to allocate IRQs top-down, starting with a high number.
+	 * 250 and 230 have been tried, but got rejected by Xen.
+	 *
+	 * Xen 3.5 also rejects 200. Try out all values until Xen accepts
+	 * or none is available.
+	 */
+	static int xen_next_irq = 200;
+	struct ioapic_softc *ioapic = ioapic_find(APIC_IRQ_APIC(*pirq));
+	struct pic *pic = &ioapic->sc_pic;
+	int pin = APIC_IRQ_PIN(*pirq);
+	physdev_op_t op;
+
+	if (*pirq & APIC_INT_VIA_APIC) {
+		irq = vect2irq[ioapic->sc_pins[pin].ip_vector];
+		if (ioapic->sc_pins[pin].ip_vector == 0 || irq == 0) {
+			/* allocate IRQ */
+			irq = APIC_IRQ_LEGACY_IRQ(*pirq);
+			if (irq <= 0 || irq > 15)
+				irq = xen_next_irq--;
+retry:
+			/* allocate vector and route interrupt */
+			op.cmd = PHYSDEVOP_ASSIGN_VECTOR;
+			op.u.irq_op.irq = irq;
+			if (HYPERVISOR_physdev_op(&op) < 0) {
+				irq = xen_next_irq--;
+				if (xen_next_irq == 15)
+					panic("PHYSDEVOP_ASSIGN_VECTOR irq %d", irq);
+				goto retry;
+			}
+			irq2vect[irq] = op.u.irq_op.vector;
+			vect2irq[op.u.irq_op.vector] = irq;
+			pic->pic_addroute(pic, &phycpu_info_primary, pin,
+			    op.u.irq_op.vector, type);
+		}
+		*pirq &= ~0xff;
+		*pirq |= irq;
+	}
+#endif /* NIOAPIC */
+	return irq2port[irq];
+}





Home | Main Index | Thread Index | Old Index