Index: sys/dev/xen/bus/xen_intr.c =================================================================== --- sys/dev/xen/bus/xen_intr.c +++ sys/dev/xen/bus/xen_intr.c @@ -263,7 +263,7 @@ * \return A pointer to a free Xen interrupt source object or NULL. */ static struct xenisrc * -xen_intr_find_unused_isrc(enum evtchn_type type) +xen_intr_find_unused_isrc(void) { int isrc_idx; @@ -287,7 +287,7 @@ isrc->xi_type == EVTCHN_TYPE_UNBOUND) { KASSERT(isrc->xi_intsrc.is_handlers == 0, ("Free evtchn still has handlers")); - isrc->xi_type = type; + isrc->xi_type = ~EVTCHN_TYPE_UNBOUND; /* mark allocated */ return (isrc); } } @@ -303,7 +303,7 @@ * object or NULL. */ static struct xenisrc * -xen_intr_alloc_isrc(enum evtchn_type type) +xen_intr_alloc_isrc(const struct xenisrc *const params) { static int warned; struct xenisrc *isrc; @@ -311,10 +311,10 @@ int error; mtx_lock(&xen_intr_isrc_lock); - isrc = xen_intr_find_unused_isrc(type); + isrc = xen_intr_find_unused_isrc(); if (isrc != NULL) { mtx_unlock(&xen_intr_isrc_lock); - return (isrc); + goto out; } if (xen_intr_auto_vector_count >= NR_EVENT_CHANNELS) { @@ -336,12 +336,16 @@ isrc = malloc(sizeof(*isrc), M_XENINTR, M_WAITOK | M_ZERO); isrc->xi_intsrc.is_pic = &xen_intr_pic; isrc->xi_vector = vector; - isrc->xi_type = type; + isrc->xi_type = ~EVTCHN_TYPE_UNBOUND; /* mark allocated */ error = intr_register_source(vector, &isrc->xi_intsrc); if (error != 0) panic("%s(): failed registering interrupt %u, error=%d\n", __func__, vector, error); +out: ; + CTASSERT(offsetof(struct xenisrc, xi_intsrc) == 0); + memcpy(&isrc->xi_intsrc + 1, ¶ms->xi_intsrc + 1, + sizeof(struct xenisrc) - sizeof(struct intsrc)); return (isrc); } @@ -381,7 +385,6 @@ isrc->xi_cpu = 0; isrc->xi_type = EVTCHN_TYPE_UNBOUND; isrc->xi_port = INVALID_EVTCHN; - isrc->xi_cookie = NULL; mtx_unlock(&xen_intr_isrc_lock); return (0); } @@ -392,8 +395,9 @@ * * \param isrcp The returned Xen interrupt object associated with * the specified local port. - * \param local_port The event channel to bind. - * \param type The event channel type of local_port. + * \param params Template xenisrc which can be used to initialize most + * xenisrc fields. Usually BIND_PARAMS() is used to + * initialize this. * \param intr_owner The device making this bind request. * \param filter An interrupt filter handler. Specify NULL * to always dispatch to the ithread handler. @@ -407,15 +411,22 @@ * * \returns 0 on success, otherwise an errno. */ +#define BIND_PARAMS(type, ...) \ +{ \ + .xi_cookie = NULL, \ + .xi_type = (type), \ + __VA_ARGS__ \ +} static int -xen_intr_bind_isrc(struct xenisrc **isrcp, evtchn_port_t local_port, - enum evtchn_type type, const char *intr_owner, driver_filter_t filter, - driver_intr_t handler, void *arg, enum intr_type flags, - xen_intr_handle_t *const port_handlep) +xen_intr_bind_isrc(struct xenisrc **isrcp, const struct xenisrc *const params, + const char *intr_owner, driver_filter_t filter, driver_intr_t handler, + void *arg, enum intr_type flags, xen_intr_handle_t *const port_handlep) { struct xenisrc *isrc; int error; + KASSERT(params != NULL, ("%s: NULL params passed in", __func__)); + *isrcp = NULL; if (port_handlep == NULL) { printf("%s: %s: Bad event handle\n", intr_owner, __func__); @@ -423,17 +434,23 @@ } *port_handlep = NULL; - isrc = xen_intr_alloc_isrc(type); + KASSERT((params->xi_type > EVTCHN_TYPE_UNBOUND) && + (params->xi_type < EVTCHN_TYPE_COUNT), + ("%s: Called with invalid event channel type (%d)", __func__, + params->xi_type)); + + isrc = xen_intr_alloc_isrc(params); if (isrc == NULL) return (ENOSPC); - isrc->xi_port = local_port; refcount_init(&isrc->xi_refcount, 1); mtx_lock(&xen_intr_isrc_lock); xen_intr_port_to_isrc[isrc->xi_port] = isrc; mtx_unlock(&xen_intr_isrc_lock); + /* ->xi_cookie is cleared by BIND_PARAMS() */ + #ifdef SMP - if (type == EVTCHN_TYPE_PORT) { + if (isrc->xi_type == EVTCHN_TYPE_PORT) { /* * By default all interrupts are assigned to vCPU#0 * unless specified otherwise, so shuffle them to balance @@ -994,20 +1011,17 @@ enum intr_type flags, xen_intr_handle_t *port_handlep) { struct xenisrc *isrc; - int error; - - error = xen_intr_bind_isrc(&isrc, local_port, EVTCHN_TYPE_PORT, - device_get_nameunit(dev), filter, handler, arg, flags, - port_handlep); - if (error != 0) - return (error); - /* * The Event Channel API didn't open this port, so it is not * responsible for closing it automatically on unbind. */ - isrc->xi_close = 0; - return (0); + struct xenisrc params = BIND_PARAMS(EVTCHN_TYPE_PORT, + .xi_close = 0, + .xi_port = local_port, + ); + + return (xen_intr_bind_isrc(&isrc, ¶ms, device_get_nameunit(dev), + filter, handler, arg, flags, port_handlep)); } int @@ -1016,6 +1030,7 @@ enum intr_type flags, xen_intr_handle_t *port_handlep) { struct xenisrc *isrc; + struct xenisrc params = BIND_PARAMS(EVTCHN_TYPE_PORT); struct evtchn_alloc_unbound alloc_unbound; int error; @@ -1031,9 +1046,9 @@ return (-error); } - error = xen_intr_bind_isrc(&isrc, alloc_unbound.port, EVTCHN_TYPE_PORT, - device_get_nameunit(dev), filter, handler, arg, flags, - port_handlep); + params.xi_port = alloc_unbound.port; + error = xen_intr_bind_isrc(&isrc, ¶ms, device_get_nameunit(dev), + filter, handler, arg, flags, port_handlep); if (error != 0) { evtchn_close_t close = { .port = alloc_unbound.port }; if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)) @@ -1051,6 +1066,7 @@ void *arg, enum intr_type flags, xen_intr_handle_t *port_handlep) { struct xenisrc *isrc; + struct xenisrc params = BIND_PARAMS(EVTCHN_TYPE_PORT); struct evtchn_bind_interdomain bind_interdomain; int error; @@ -1066,9 +1082,9 @@ return (-error); } - error = xen_intr_bind_isrc(&isrc, bind_interdomain.local_port, - EVTCHN_TYPE_PORT, device_get_nameunit(dev), filter, handler, arg, - flags, port_handlep); + params.xi_port = bind_interdomain.local_port; + error = xen_intr_bind_isrc(&isrc, ¶ms, device_get_nameunit(dev), + filter, handler, arg, flags, port_handlep); if (error) { evtchn_close_t close = { .port = bind_interdomain.local_port }; if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)) @@ -1091,6 +1107,9 @@ { u_int vcpu_id = XEN_CPUID_TO_VCPUID(cpu); struct xenisrc *isrc; + struct xenisrc params = BIND_PARAMS(EVTCHN_TYPE_VIRQ, + .xi_virq = virq, + ); struct evtchn_bind_virq bind_virq = { .virq = virq, .vcpu = vcpu_id }; int error; @@ -1104,9 +1123,9 @@ return (-error); } - error = xen_intr_bind_isrc(&isrc, bind_virq.port, EVTCHN_TYPE_VIRQ, - device_get_nameunit(dev), filter, handler, arg, flags, - port_handlep); + params.xi_port = bind_virq.port; + error = xen_intr_bind_isrc(&isrc, ¶ms, device_get_nameunit(dev), + filter, handler, arg, flags, port_handlep); #ifdef SMP if (error == 0) @@ -1140,7 +1159,6 @@ * responsible for closing it automatically on unbind. */ isrc->xi_close = 1; - isrc->xi_virq = virq; return (0); } @@ -1152,6 +1170,7 @@ #ifdef SMP u_int vcpu_id = XEN_CPUID_TO_VCPUID(cpu); struct xenisrc *isrc; + struct xenisrc params = BIND_PARAMS(EVTCHN_TYPE_IPI); struct evtchn_bind_ipi bind_ipi = { .vcpu = vcpu_id }; /* Same size as the one used by intr_handler->ih_name. */ char name[MAXCOMLEN + 1]; @@ -1167,10 +1186,11 @@ return (-error); } + params.xi_port = bind_ipi.port; snprintf(name, sizeof(name), "cpu%u", cpu); - error = xen_intr_bind_isrc(&isrc, bind_ipi.port, EVTCHN_TYPE_IPI, - name, filter, NULL, NULL, flags, port_handlep); + error = xen_intr_bind_isrc(&isrc, ¶ms, name, filter, NULL, NULL, + flags, port_handlep); if (error != 0) { evtchn_close_t close = { .port = bind_ipi.port };