svn commit: r273473 - in head/sys: x86/xen xen
Roger Pau Monné
royger at FreeBSD.org
Wed Oct 22 16:51:53 UTC 2014
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_ */
More information about the svn-src-all
mailing list