From a483ba0df96582395822d327778650014a7ce4eb Mon Sep 17 00:00:00 2001
From: Julien Grall <julien.grall@linaro.org>
Date: Tue, 14 Jan 2014 01:41:04 +0000
Subject: [PATCH 32/48] xen/intr: Rework the event channels handler to make it
 generic

The current code to handle the event channels was x86-specific. I think
we can use safely generic function to handle interrupt.

This code was not yet tested/compiled on x86.

TODO:
	- There is some #if 0 in the code. Mainly for suspend/resume
---
 sys/xen/xen_intr.c | 184 +++++++++++++++++++++--------------------------------
 1 file changed, 74 insertions(+), 110 deletions(-)

diff --git a/sys/xen/xen_intr.c b/sys/xen/xen_intr.c
index a259824..84e528a 100644
--- a/sys/xen/xen_intr.c
+++ b/sys/xen/xen_intr.c
@@ -50,8 +50,6 @@ __FBSDID("$FreeBSD$");
 #include <vm/pmap.h>
 
 #include <machine/intr_machdep.h>
-#include <x86/apicvar.h>
-#include <x86/apicreg.h>
 #include <machine/smp.h>
 #include <machine/stdarg.h>
 
@@ -63,7 +61,6 @@ __FBSDID("$FreeBSD$");
 #include <xen/xen_intr.h>
 #include <xen/evtchn/evtchnvar.h>
 
-#include <dev/xen/xenpci/xenpcivar.h>
 #include <dev/pci/pcivar.h>
 
 #ifdef DDB
@@ -117,10 +114,9 @@ DPCPU_DECLARE(struct vcpu_info *, vcpu_info);
 #define	is_valid_evtchn(x)	((x) != XEN_INVALID_EVTCHN)
 
 struct xenisrc {
-	struct intsrc	xi_intsrc;
+	struct intr_event *xi_event;
 	enum evtchn_type xi_type;
 	int		xi_cpu;		/* VCPU for delivery. */
-	int		xi_vector;	/* Global isrc vector number. */
 	evtchn_port_t	xi_port;
 	int		xi_pirq;
 	int		xi_virq;
@@ -133,60 +129,10 @@ struct xenisrc {
 
 #define ARRAY_SIZE(a)	(sizeof(a) / sizeof(a[0]))
 
-static void	xen_intr_suspend(struct pic *);
-static void	xen_intr_resume(struct pic *, bool suspend_cancelled);
-static void	xen_intr_enable_source(struct intsrc *isrc);
-static void	xen_intr_disable_source(struct intsrc *isrc, int eoi);
-static void	xen_intr_eoi_source(struct intsrc *isrc);
-static void	xen_intr_enable_intr(struct intsrc *isrc);
-static void	xen_intr_disable_intr(struct intsrc *isrc);
-static int	xen_intr_vector(struct intsrc *isrc);
-static int	xen_intr_source_pending(struct intsrc *isrc);
-static int	xen_intr_config_intr(struct intsrc *isrc,
-		     enum intr_trigger trig, enum intr_polarity pol);
-static int	xen_intr_assign_cpu(struct intsrc *isrc, u_int to_cpu);
-static int	xen_pic_assign_cpu(struct intsrc *isrc, u_int apic_id);
-
-static void	xen_intr_pirq_enable_source(struct intsrc *isrc);
-static void	xen_intr_pirq_disable_source(struct intsrc *isrc, int eoi);
-static void	xen_intr_pirq_eoi_source(struct intsrc *isrc);
-static void	xen_intr_pirq_enable_intr(struct intsrc *isrc);
-static void	xen_intr_pirq_disable_intr(struct intsrc *isrc);
-static int	xen_intr_pirq_config_intr(struct intsrc *isrc,
-		     enum intr_trigger trig, enum intr_polarity pol);
+static void	xen_intr_enable_intr(void *arg);
+static void	xen_intr_disable_intr(void *arg);
 
-/**
- * PIC interface for all event channel port types except physical IRQs.
- */
-struct pic xen_intr_pic = {
-	.pic_enable_source  = xen_intr_enable_source,
-	.pic_disable_source = xen_intr_disable_source,
-	.pic_eoi_source     = xen_intr_eoi_source,
-	.pic_enable_intr    = xen_intr_enable_intr,
-	.pic_disable_intr   = xen_intr_disable_intr,
-	.pic_vector         = xen_intr_vector,
-	.pic_source_pending = xen_intr_source_pending,
-	.pic_suspend        = xen_intr_suspend,
-	.pic_resume         = xen_intr_resume,
-	.pic_config_intr    = xen_intr_config_intr,
-	.pic_assign_cpu     = xen_pic_assign_cpu
-};
-
-/**
- * PIC interface for all event channel representing
- * physical interrupt sources.
- */
-struct pic xen_intr_pirq_pic = {
-	.pic_enable_source  = xen_intr_pirq_enable_source,
-	.pic_disable_source = xen_intr_pirq_disable_source,
-	.pic_eoi_source     = xen_intr_pirq_eoi_source,
-	.pic_enable_intr    = xen_intr_pirq_enable_intr,
-	.pic_disable_intr   = xen_intr_pirq_disable_intr,
-	.pic_vector         = xen_intr_vector,
-	.pic_source_pending = xen_intr_source_pending,
-	.pic_config_intr    = xen_intr_pirq_config_intr,
-	.pic_assign_cpu     = xen_pic_assign_cpu
-};
+static int	xen_intr_assign_cpu(struct xenisrc *isrc, u_int to_cpu);
 
 static struct mtx	 xen_intr_isrc_lock;
 static int		 xen_intr_auto_vector_count;
@@ -250,12 +196,16 @@ xen_intr_intrcnt_add(u_int cpu)
 	char buf[MAXCOMLEN + 1];
 	struct xen_intr_pcpu_data *pcpu;
 
+	static u_long count = 0;
+
 	pcpu = DPCPU_ID_PTR(cpu, xen_intr_pcpu);
 	if (pcpu->evtchn_intrcnt != NULL)
 		return;
 
 	snprintf(buf, sizeof(buf), "cpu%d:xen", cpu);
-	intrcnt_add(buf, &pcpu->evtchn_intrcnt);
+
+	/* TODO: handle correctly IRQ counter */
+	pcpu->evtchn_intrcnt = &count;
 }
 
 /**
@@ -270,6 +220,7 @@ xen_intr_intrcnt_add(u_int cpu)
 static struct xenisrc *
 xen_intr_find_unused_isrc(enum evtchn_type type)
 {
+#if 0
 	int isrc_idx;
 
 	KASSERT(mtx_owned(&xen_intr_isrc_lock), ("Evtchn isrc lock not held"));
@@ -288,6 +239,7 @@ xen_intr_find_unused_isrc(enum evtchn_type type)
 			return (isrc);
 		}
 	}
+#endif
 	return (NULL);
 }
 
@@ -304,6 +256,7 @@ xen_intr_alloc_isrc(enum evtchn_type type, int vector)
 {
 	static int warned;
 	struct xenisrc *isrc;
+	int error;
 
 	KASSERT(mtx_owned(&xen_intr_isrc_lock), ("Evtchn alloc lock not held"));
 
@@ -320,18 +273,24 @@ xen_intr_alloc_isrc(enum evtchn_type type, int vector)
 		xen_intr_auto_vector_count++;
 	}
 
-	KASSERT((intr_lookup_source(vector) == NULL),
-	    ("Trying to use an already allocated vector"));
-
 	mtx_unlock(&xen_intr_isrc_lock);
 	isrc = malloc(sizeof(*isrc), M_XENINTR, M_WAITOK | M_ZERO);
-	isrc->xi_intsrc.is_pic =
-	    (type == EVTCHN_TYPE_PIRQ) ? &xen_intr_pirq_pic : &xen_intr_pic;
-	isrc->xi_vector = vector;
 	isrc->xi_type = type;
-	intr_register_source(&isrc->xi_intsrc);
+	/* TODO: Make the name of the event more accurate */
+	error = intr_event_create(&isrc->xi_event, isrc, 0, vector /* IRQ */,
+				  xen_intr_disable_intr /* mask */,
+				  xen_intr_enable_intr /* unmask */,
+				  NULL /* EOI */,
+				  NULL /* cpu assign */, "xen%d:", vector);
 	mtx_lock(&xen_intr_isrc_lock);
 
+	if (error) {
+		printf("%s: event creation failed (%d)\n",
+		       __FUNCTION__, error);
+		free(isrc, M_XENINTR);
+		isrc = NULL;
+	}
+
 	return (isrc);
 }
 
@@ -347,7 +306,8 @@ xen_intr_release_isrc(struct xenisrc *isrc)
 {
 
 	mtx_lock(&xen_intr_isrc_lock);
-	if (isrc->xi_intsrc.is_handlers != 0) {
+
+	if (!TAILQ_EMPTY(&isrc->xi_event->ie_handlers)) {
 		mtx_unlock(&xen_intr_isrc_lock);
 		return (EBUSY);
 	}
@@ -358,6 +318,8 @@ xen_intr_release_isrc(struct xenisrc *isrc)
 	evtchn_cpu_mask_port(isrc->xi_cpu, isrc->xi_port);
 	evtchn_cpu_unmask_port(0, isrc->xi_port);
 
+	intr_event_destroy(isrc->xi_event);
+
 	if (isrc->xi_close != 0 && is_valid_evtchn(isrc->xi_port)) {
 		struct evtchn_close close = { .port = isrc->xi_port };
 		if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close))
@@ -501,12 +463,13 @@ void
 xen_intr_handle_upcall(struct trapframe *trap_frame)
 {
 	u_int l1i, l2i, port, cpu;
-	u_long masked_l1, masked_l2;
+	xen_ulong_t masked_l1, masked_l2;
 	struct xenisrc *isrc;
 	shared_info_t *s;
 	vcpu_info_t *v;
 	struct xen_intr_pcpu_data *pc;
-	u_long l1, l2;
+	xen_ulong_t l1, l2;
+	int error;
 
 	/*
 	 * Disable preemption in order to always check and fire events
@@ -525,14 +488,11 @@ xen_intr_handle_upcall(struct trapframe *trap_frame)
 
 	v->evtchn_upcall_pending = 0;
 
-#if 0
-#ifndef CONFIG_X86 /* No need for a barrier -- XCHG is a barrier on x86. */
-	/* Clear master flag /before/ clearing selector flag. */
-	wmb();
-#endif
-#endif
-
-	l1 = atomic_readandclear_long(&v->evtchn_pending_sel);
+	/*
+	 * Clear master flags /before/ clearing selector flag.
+	 * atomic_readandclear_xen_ulong must contain an appropriate barrier
+	 */
+	l1 = atomic_readandclear_xen_ulong(&v->evtchn_pending_sel);
 
 	l1i = pc->last_processed_l1i;
 	l2i = pc->last_processed_l2i;
@@ -580,7 +540,9 @@ xen_intr_handle_upcall(struct trapframe *trap_frame)
 				("Received unexpected event on vCPU#%d, event bound to vCPU#%d",
 				PCPU_GET(cpuid), isrc->xi_cpu));
 
-			intr_execute_handlers(&isrc->xi_intsrc, trap_frame);
+			error = intr_event_handle(isrc->xi_event, trap_frame);
+			if ( error != 0 )
+				printf("stray evchn%d: %d\n", port, error);
 
 			/*
 			 * If this is the final port processed,
@@ -631,7 +593,7 @@ xen_intr_init(void *dummy __unused)
 	}
 
 	for (i = 0; i < nitems(s->evtchn_mask); i++)
-		atomic_store_rel_long(&s->evtchn_mask[i], ~0);
+		atomic_store_rel_xen_ulong(&s->evtchn_mask[i], ~0);
 
 	/* Try to register PIRQ EOI map */
 	xen_intr_pirq_eoi_map = malloc(PAGE_SIZE, M_XENINTR, M_WAITOK | M_ZERO);
@@ -642,9 +604,6 @@ xen_intr_init(void *dummy __unused)
 	else
 		xen_intr_pirq_eoi_map_enabled = true;
 
-	intr_register_pic(&xen_intr_pic);
-	intr_register_pic(&xen_intr_pirq_pic);
-
 	if (bootverbose)
 		printf("Xen interrupt system initialized\n");
 
@@ -653,9 +612,8 @@ xen_intr_init(void *dummy __unused)
 SYSINIT(xen_intr_init, SI_SUB_INTR, SI_ORDER_SECOND, xen_intr_init, NULL);
 
 /*--------------------------- Common PIC Functions ---------------------------*/
-/**
- * Prepare this PIC for system suspension.
- */
+
+#if 0
 static void
 xen_intr_suspend(struct pic *unused)
 {
@@ -770,6 +728,7 @@ xen_intr_resume(struct pic *unused, bool suspend_cancelled)
 		}
 	}
 }
+#endif
 
 /**
  * Disable a Xen interrupt source.
@@ -777,13 +736,14 @@ xen_intr_resume(struct pic *unused, bool suspend_cancelled)
  * \param isrc  The interrupt source to disable.
  */
 static void
-xen_intr_disable_intr(struct intsrc *base_isrc)
+xen_intr_disable_intr(void *arg)
 {
-	struct xenisrc *isrc = (struct xenisrc *)base_isrc;
+	struct xenisrc *isrc = arg;
 
 	evtchn_mask_port(isrc->xi_port);
 }
 
+#if 0
 /**
  * Determine the global interrupt vector number for
  * a Xen interrupt source.
@@ -835,6 +795,8 @@ xen_intr_config_intr(struct intsrc *isrc, enum intr_trigger trig,
 	return (ENODEV);
 }
 
+#endif
+
 /**
  * Configure CPU affinity for interrupt source event delivery.
  *
@@ -844,11 +806,10 @@ xen_intr_config_intr(struct intsrc *isrc, enum intr_trigger trig,
  * \returns  0 if successful, otherwise an errno.
  */
 static int
-xen_intr_assign_cpu(struct intsrc *base_isrc, u_int to_cpu)
+xen_intr_assign_cpu(struct xenisrc *isrc, u_int to_cpu)
 {
 #ifdef SMP
 	struct evtchn_bind_vcpu bind_vcpu;
-	struct xenisrc *isrc;
 	u_int vcpu_id = cpu_to_vcpu_id(to_cpu);
 	int error;
 
@@ -860,7 +821,6 @@ xen_intr_assign_cpu(struct intsrc *base_isrc, u_int to_cpu)
 	xen_intr_intrcnt_add(to_cpu);
 
 	mtx_lock(&xen_intr_isrc_lock);
-	isrc = (struct xenisrc *)base_isrc;
 	if (!is_valid_evtchn(isrc->xi_port)) {
 		mtx_unlock(&xen_intr_isrc_lock);
 		return (EINVAL);
@@ -907,14 +867,8 @@ out:
 #endif
 }
 
-/* Wrapper of xen_intr_assign_cpu to use as pic callbacks */
-static int
-xen_pic_assign_cpu(struct intsrc *isrc, u_int apic_id)
-{
-	return xen_intr_assign_cpu(isrc, apic_cpuid(apic_id));
-}
-
 /*------------------- Virtual Interrupt Source PIC Functions -----------------*/
+#if 0
 /*
  * Mask a level triggered interrupt source.
  *
@@ -947,19 +901,21 @@ xen_intr_eoi_source(struct intsrc *isrc)
 {
 }
 
+#endif
 /*
  * Enable and unmask the interrupt source.
  *
  * \param isrc  The interrupt source to enable.
  */
 static void
-xen_intr_enable_intr(struct intsrc *base_isrc)
+xen_intr_enable_intr(void *arg)
 {
-	struct xenisrc *isrc = (struct xenisrc *)base_isrc;
+	struct xenisrc *isrc = arg;
 
 	evtchn_unmask_port(isrc->xi_port);
 }
 
+#if 0
 /*------------------ Physical Interrupt Source PIC Functions -----------------*/
 /*
  * Mask a level triggered interrupt source.
@@ -1130,6 +1086,7 @@ xen_intr_pirq_config_intr(struct intsrc *base_isrc, enum intr_trigger trig,
 
 	return (0);
 }
+#endif
 
 /*--------------------------- Public Functions -------------------------------*/
 /*------- API comments for these methods can be found in xen/xenintr.h -------*/
@@ -1151,7 +1108,7 @@ xen_intr_bind_local_port(device_t dev, evtchn_port_t local_port,
 	 * unless specified otherwise, so shuffle them to balance
 	 * the interrupt load.
 	 */
-	xen_intr_assign_cpu(&isrc->xi_intsrc, intr_next_cpu());
+	xen_intr_assign_cpu(isrc, intr_next_cpu());
 
 	/*
 	 * The Event Channel API didn't open this port, so it is not
@@ -1197,7 +1154,7 @@ xen_intr_alloc_and_bind_local_port(device_t dev, u_int remote_domain,
 	 * unless specified otherwise, so shuffle them to balance
 	 * the interrupt load.
 	 */
-	xen_intr_assign_cpu(&isrc->xi_intsrc, intr_next_cpu());
+	xen_intr_assign_cpu(isrc, intr_next_cpu());
 
 	isrc->xi_close = 1;
 	return (0);
@@ -1239,7 +1196,7 @@ xen_intr_bind_remote_port(device_t dev, u_int remote_domain,
 	 * unless specified otherwise, so shuffle them to balance
 	 * the interrupt load.
 	 */
-	xen_intr_assign_cpu(&isrc->xi_intsrc, intr_next_cpu());
+	xen_intr_assign_cpu(isrc, intr_next_cpu());
 
 	/*
 	 * The Event Channel API opened this port, so it is
@@ -1277,7 +1234,7 @@ xen_intr_bind_virq(device_t dev, u_int virq, u_int cpu,
 
 #ifdef SMP
 	if (error == 0)
-		error = intr_event_bind(isrc->xi_intsrc.is_event, cpu);
+		error = intr_event_bind(isrc->xi_event, cpu);
 #endif
 
 	if (error != 0) {
@@ -1297,7 +1254,7 @@ xen_intr_bind_virq(device_t dev, u_int virq, u_int cpu,
 		 * masks manually so events can't fire on the wrong cpu
 		 * during AP startup.
 		 */
-		xen_intr_assign_cpu(&isrc->xi_intsrc, cpu);
+		xen_intr_assign_cpu(isrc, cpu);
 	}
 #endif
 
@@ -1339,7 +1296,7 @@ xen_intr_alloc_and_bind_ipi(device_t dev, u_int cpu,
 	                           dev, filter, NULL, NULL, flags,
 	                           port_handlep);
 	if (error == 0)
-		error = intr_event_bind(isrc->xi_intsrc.is_event, cpu);
+		error = intr_event_bind(isrc->xi_event, cpu);
 
 	if (error != 0) {
 		evtchn_close_t close = { .port = bind_ipi.port };
@@ -1357,7 +1314,7 @@ xen_intr_alloc_and_bind_ipi(device_t dev, u_int cpu,
 		 * masks manually so events can't fire on the wrong cpu
 		 * during AP startup.
 		 */
-		xen_intr_assign_cpu(&isrc->xi_intsrc, cpu);
+		xen_intr_assign_cpu(isrc, cpu);
 	}
 
 	/*
@@ -1452,6 +1409,7 @@ xen_register_msi(device_t dev, int vector, int count)
 	return (0);
 }
 
+#if 0
 int
 xen_release_msi(int vector)
 {
@@ -1472,6 +1430,7 @@ xen_release_msi(int vector)
 
 	return (0);
 }
+#endif
 
 int
 xen_intr_describe(xen_intr_handle_t port_handle, const char *fmt, ...)
@@ -1487,7 +1446,9 @@ xen_intr_describe(xen_intr_handle_t port_handle, const char *fmt, ...)
 	va_start(ap, fmt);
 	vsnprintf(descr, sizeof(descr), fmt, ap);
 	va_end(ap);
-	return (intr_describe(isrc->xi_vector, isrc->xi_cookie, descr));
+
+	return (intr_event_describe_handler(isrc->xi_event, port_handle,
+					    descr));
 }
 
 void
@@ -1504,7 +1465,7 @@ xen_intr_unbind(xen_intr_handle_t *port_handlep)
 		return;
 
 	if (isrc->xi_cookie != NULL)
-		intr_remove_handler(isrc->xi_cookie);
+		intr_event_remove_handler(isrc->xi_cookie);
 	xen_intr_release_isrc(isrc);
 }
 
@@ -1547,8 +1508,11 @@ xen_intr_add_handler(device_t dev, driver_filter_t filter,
 	if (isrc == NULL || isrc->xi_cookie != NULL)
 		return (EINVAL);
 
-	error = intr_add_handler(device_get_nameunit(dev), isrc->xi_vector,
-	    filter, handler, arg, flags|INTR_EXCL, &isrc->xi_cookie);
+	error = intr_event_add_handler(isrc->xi_event,
+				       device_get_nameunit(dev),
+				       filter, handler, arg,
+				       intr_priority(flags), flags|INTR_EXCL,
+				       isrc->xi_cookie);
 	if (error != 0) {
 		device_printf(dev,
 		    "xen_intr_add_handler: intr_add_handler failed: %d\n",
-- 
2.1.0

