From: Julien Grall Date: Tue, 14 Jan 2014 01:41:04 +0000 (+0000) Subject: xen/intr: Rework the event channels handler to make it generic X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=8d64cb89afda9c496f7889e354b195e30e17e603;p=people%2Fjulieng%2Ffreebsd.git 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 --- diff --git a/sys/xen/xen_intr.c b/sys/xen/xen_intr.c index f1221d6ad8e6..e5c12af89ce7 100644 --- a/sys/xen/xen_intr.c +++ b/sys/xen/xen_intr.c @@ -50,8 +50,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include #include #include @@ -62,7 +60,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include #ifdef DDB @@ -116,10 +113,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; @@ -132,60 +128,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; @@ -249,12 +195,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; } /** @@ -269,6 +219,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")); @@ -287,6 +238,7 @@ xen_intr_find_unused_isrc(enum evtchn_type type) return (isrc); } } +#endif return (NULL); } @@ -303,6 +255,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")); @@ -319,18 +272,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); } @@ -346,7 +305,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); } @@ -357,6 +317,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)) @@ -511,12 +473,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 @@ -535,14 +498,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; @@ -590,7 +550,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, @@ -641,7 +603,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); @@ -652,9 +614,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"); @@ -663,9 +622,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) { @@ -780,6 +738,7 @@ xen_intr_resume(struct pic *unused, bool suspend_cancelled) } } } +#endif /** * Disable a Xen interrupt source. @@ -787,13 +746,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. @@ -845,6 +805,8 @@ xen_intr_config_intr(struct intsrc *isrc, enum intr_trigger trig, return (ENODEV); } +#endif + /** * Configure CPU affinity for interrupt source event delivery. * @@ -854,11 +816,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; @@ -868,7 +829,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); @@ -915,14 +875,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. * @@ -974,19 +928,21 @@ xen_intr_eoi_source(struct intsrc *base_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. @@ -1164,6 +1120,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 -------*/ @@ -1290,7 +1247,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) { @@ -1310,7 +1267,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 @@ -1352,7 +1309,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 }; @@ -1370,7 +1327,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); } /* @@ -1458,6 +1415,7 @@ xen_register_msi(device_t dev, int vector, int count) return (0); } +#if 0 int xen_release_msi(int vector) { @@ -1478,6 +1436,7 @@ xen_release_msi(int vector) return (0); } +#endif int xen_intr_describe(xen_intr_handle_t port_handle, const char *fmt, ...) @@ -1493,7 +1452,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 @@ -1510,7 +1471,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); } @@ -1553,8 +1514,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",