Index: sys/dev/xen/bus/xen_intr.c =================================================================== --- sys/dev/xen/bus/xen_intr.c +++ sys/dev/xen/bus/xen_intr.c @@ -200,7 +200,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; @@ -224,7 +224,7 @@ isrc->xi_type == EVTCHN_TYPE_UNBOUND) { KASSERT(!xen_arch_intr_has_handlers(isrc), ("Free evtchn still has handlers")); - isrc->xi_type = type; + isrc->xi_type = EVTCHN_TYPE_COUNT; /* mark allocated */ return (isrc); } } @@ -240,7 +240,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; @@ -248,10 +248,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) { @@ -273,12 +273,16 @@ isrc = malloc(sizeof(*isrc), M_XENINTR, M_WAITOK | M_ZERO); isrc->xi_arch.intsrc.is_pic = &xen_intr_pic; isrc->xi_arch.vector = vector; - isrc->xi_type = type; + isrc->xi_type = EVTCHN_TYPE_COUNT; /* mark allocated */ error = intr_register_source(&isrc->xi_arch.intsrc); if (error != 0) panic("%s(): failed registering interrupt %u, error=%d\n", __func__, vector, error); +out: ; + CTASSERT(offsetof(struct xenisrc, xi_arch) == 0); + memcpy(&isrc->xi_arch + 1, ¶ms->xi_arch + 1, + sizeof(struct xenisrc) - sizeof(xen_arch_isrc_t)); return (isrc); } @@ -318,7 +322,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); } @@ -329,8 +332,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. @@ -344,11 +348,16 @@ * * \returns 0 on success, otherwise an errno. */ +#define BIND_PARAMS(type, ...) \ +{ \ + .xi_type = (type), \ + .xi_cookie = NULL, \ + __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 *port_handlep) +xen_intr_bind_isrc(struct xenisrc **isrcp, const struct xenisrc *params, + const char *intr_owner, driver_filter_t filter, driver_intr_t handler, + void *arg, enum intr_type flags, xen_intr_handle_t *port_handlep) { struct xenisrc *isrc; int error; @@ -359,10 +368,9 @@ return (EINVAL); } - isrc = xen_intr_alloc_isrc(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; @@ -371,8 +379,10 @@ /* Assign the opaque handler */ *port_handlep = xen_intr_handle_from_isrc(isrc); + /* ->xi_cookie is cleared in 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 @@ -838,20 +848,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); + struct xenisrc params = BIND_PARAMS(EVTCHN_TYPE_PORT, + .xi_port = local_port, + /* + * The Event Channel API didn't open this port, so it is not + * responsible for closing it automatically on unbind. + */ + .xi_close = 0, + ); - /* - * 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); + return (xen_intr_bind_isrc(&isrc, ¶ms, device_get_nameunit(dev), + filter, handler, arg, flags, port_handlep)); } int @@ -860,6 +867,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; @@ -875,11 +883,11 @@ 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 }; + evtchn_close_t close = { .port = params.xi_port }; if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)) panic("EVTCHNOP_close failed"); return (error); @@ -895,6 +903,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; @@ -910,11 +919,11 @@ 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 }; + evtchn_close_t close = { .port = params.xi_port }; if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)) panic("EVTCHNOP_close failed"); return (error); @@ -935,6 +944,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; @@ -948,9 +960,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) @@ -958,7 +970,7 @@ #endif if (error != 0) { - evtchn_close_t close = { .port = bind_virq.port }; + evtchn_close_t close = { .port = params.xi_port }; xen_intr_unbind(*port_handlep); if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)) @@ -983,7 +995,6 @@ * responsible for closing it automatically on unbind. */ isrc->xi_close = 1; - isrc->xi_virq = virq; return (0); } @@ -995,6 +1006,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]; @@ -1010,12 +1022,13 @@ 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 }; + evtchn_close_t close = { .port = params.xi_port }; xen_intr_unbind(*port_handlep); if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close))