Date: Wed, 22 Oct 2014 16:51:52 +0000 (UTC) From: Roger Pau Monné <royger@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r273473 - in head/sys: x86/xen xen Message-ID: <201410221651.s9MGpq0b053474@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: royger Date: Wed Oct 22 16:51:52 2014 New Revision: 273473 URL: https://svnweb.freebsd.org/changeset/base/273473 Log: xen: allow to register event channels without handlers This is needed by the event channel user-space device, that requires registering event channels without unmasking them. intr_add_handler will unconditionally unmask the event channel, so we avoid calling it if no filter/handler is provided, and then the user will be in charge of calling it when ready. In order to do this, we need to change the opaque type xen_intr_handle_t to contain the event channel port instead of the opaque cookie returned by intr_add_handler, since now registration of event channels without handlers are allowed. The cookie will now be stored inside of the private xenisrc struct. Also, introduce a new function called xen_intr_add_handler that allows adding a filter/handler after the event channel has been registered. Sponsored by: Citrix Systems R&D x86/xen/xen_intr.c: - Leave the event channel without a handler if no filter/handler is provided to xen_intr_bind_isrc. - Don't perform an evtchn_mask_port, intr_add_handler will already do it. - Change the opaque type xen_intr_handle_t to contain a pointer to the event channel port number, and make the necessary changes to related functions. - Introduce a new function called xen_intr_add_handler that can be used to add filter/handlers to an event channel after registration. xen/xen_intr.h: - Add prototype of xen_intr_add_handler. Modified: head/sys/x86/xen/xen_intr.c head/sys/xen/xen_intr.h Modified: head/sys/x86/xen/xen_intr.c ============================================================================== --- head/sys/x86/xen/xen_intr.c Wed Oct 22 16:49:00 2014 (r273472) +++ head/sys/x86/xen/xen_intr.c Wed Oct 22 16:51:52 2014 (r273473) @@ -110,10 +110,11 @@ DPCPU_DEFINE(struct xen_intr_pcpu_data, DPCPU_DECLARE(struct vcpu_info *, vcpu_info); -#define is_valid_evtchn(x) ((x) != 0) - #define XEN_EEXIST 17 /* Xen "already exists" error */ #define XEN_ALLOCATE_VECTOR 0 /* Allocate a vector for this event channel */ +#define XEN_INVALID_EVTCHN 0 /* Invalid event channel */ + +#define is_valid_evtchn(x) ((x) != XEN_INVALID_EVTCHN) struct xenisrc { struct intsrc xi_intsrc; @@ -123,6 +124,7 @@ struct xenisrc { evtchn_port_t xi_port; int xi_pirq; int xi_virq; + void *xi_cookie; u_int xi_close:1; /* close on unbind? */ u_int xi_shared:1; /* Shared with other domains. */ u_int xi_activehi:1; @@ -365,6 +367,7 @@ xen_intr_release_isrc(struct xenisrc *is isrc->xi_cpu = 0; isrc->xi_type = EVTCHN_TYPE_UNBOUND; isrc->xi_port = 0; + isrc->xi_cookie = NULL; mtx_unlock(&xen_intr_isrc_lock); return (0); } @@ -419,17 +422,26 @@ xen_intr_bind_isrc(struct xenisrc **isrc xen_intr_port_to_isrc[local_port] = isrc; mtx_unlock(&xen_intr_isrc_lock); - error = intr_add_handler(device_get_nameunit(intr_owner), - isrc->xi_vector, filter, handler, arg, - flags|INTR_EXCL, port_handlep); + /* Assign the opaque handler (the event channel port) */ + *port_handlep = &isrc->xi_port; + + if (filter == NULL && handler == NULL) { + /* + * No filter/handler provided, leave the event channel + * masked and without a valid handler, the caller is + * in charge of setting that up. + */ + *isrcp = isrc; + return (0); + } + + error = xen_intr_add_handler(intr_owner, filter, handler, arg, flags, + *port_handlep); if (error != 0) { - device_printf(intr_owner, - "xen_intr_bind_irq: intr_add_handler failed\n"); xen_intr_release_isrc(isrc); return (error); } *isrcp = isrc; - evtchn_unmask_port(local_port); return (0); } @@ -446,13 +458,16 @@ xen_intr_bind_isrc(struct xenisrc **isrc static struct xenisrc * xen_intr_isrc(xen_intr_handle_t handle) { - struct intr_handler *ih; + evtchn_port_t port; + + if (handle == NULL) + return (NULL); - ih = handle; - if (ih == NULL || ih->ih_event == NULL) + port = *(evtchn_port_t *)handle; + if (!is_valid_evtchn(port) || port >= NR_EVENT_CHANNELS) return (NULL); - return (ih->ih_event->ie_source); + return (xen_intr_port_to_isrc[port]); } /** @@ -1446,22 +1461,24 @@ xen_intr_describe(xen_intr_handle_t port va_start(ap, fmt); vsnprintf(descr, sizeof(descr), fmt, ap); va_end(ap); - return (intr_describe(isrc->xi_vector, port_handle, descr)); + return (intr_describe(isrc->xi_vector, isrc->xi_cookie, descr)); } void xen_intr_unbind(xen_intr_handle_t *port_handlep) { - struct intr_handler *handler; struct xenisrc *isrc; - handler = *port_handlep; + KASSERT(port_handlep != NULL, + ("NULL xen_intr_handle_t passed to xen_intr_unbind")); + + isrc = xen_intr_isrc(*port_handlep); *port_handlep = NULL; - isrc = xen_intr_isrc(handler); if (isrc == NULL) return; - intr_remove_handler(handler); + if (isrc->xi_cookie != NULL) + intr_remove_handler(isrc->xi_cookie); xen_intr_release_isrc(isrc); } @@ -1492,6 +1509,29 @@ xen_intr_port(xen_intr_handle_t handle) return (isrc->xi_port); } +int +xen_intr_add_handler(device_t dev, driver_filter_t filter, + driver_intr_t handler, void *arg, enum intr_type flags, + xen_intr_handle_t handle) +{ + struct xenisrc *isrc; + int error; + + isrc = xen_intr_isrc(handle); + 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); + if (error != 0) { + device_printf(dev, + "xen_intr_add_handler: intr_add_handler failed: %d\n", + error); + } + + return (error); +} + #ifdef DDB static const char * xen_intr_print_type(enum evtchn_type type) Modified: head/sys/xen/xen_intr.h ============================================================================== --- head/sys/xen/xen_intr.h Wed Oct 22 16:49:00 2014 (r273472) +++ head/sys/xen/xen_intr.h Wed Oct 22 16:51:52 2014 (r273473) @@ -246,4 +246,23 @@ int xen_register_msi(device_t dev, int v */ int xen_release_msi(int vector); +/** + * Bind an event channel port with a handler + * + * \param dev The device making this bind request. + * \param filter An interrupt filter handler. Specify NULL + * to always dispatch to the ithread handler. + * \param handler An interrupt ithread handler. Optional (can + * specify NULL) if all necessary event actions + * are performed by filter. + * \param arg Argument to present to both filter and handler. + * \param irqflags Interrupt handler flags. See sys/bus.h. + * \param handle Opaque handle used to manage this registration. + * + * \returns 0 on success, otherwise an errno. + */ +int xen_intr_add_handler(device_t dev, driver_filter_t filter, + driver_intr_t handler, void *arg, enum intr_type flags, + xen_intr_handle_t handle); + #endif /* _XEN_INTR_H_ */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201410221651.s9MGpq0b053474>