Index: sys/dev/xen/bus/xen_intr.c =================================================================== --- sys/dev/xen/bus/xen_intr.c +++ sys/dev/xen/bus/xen_intr.c @@ -382,7 +382,6 @@ xen_intr_port_to_isrc[isrc->xi_port] = NULL; } - isrc->xi_cpu = 0; isrc->xi_type = EVTCHN_TYPE_UNBOUND; isrc->xi_port = INVALID_EVTCHN; mtx_unlock(&xen_intr_isrc_lock); @@ -411,10 +410,11 @@ * * \returns 0 on success, otherwise an errno. */ -#define BIND_PARAMS(type, ...) \ +#define BIND_PARAMS(type, cpu, ...) \ { \ .xi_cookie = NULL, \ .xi_type = (type), \ + .xi_cpu = (cpu), \ __VA_ARGS__ \ } static int @@ -424,6 +424,9 @@ { struct xenisrc *isrc; int error; +#ifdef SMP + u_int cpu; +#endif KASSERT(params != NULL, ("%s: NULL params passed in", __func__)); @@ -443,6 +446,10 @@ if (isrc == NULL) return (ENOSPC); refcount_init(&isrc->xi_refcount, 1); +#ifdef SMP + cpu = isrc->xi_cpu; + isrc->xi_cpu = 0; /* initialize to the likely correct value */ +#endif mtx_lock(&xen_intr_isrc_lock); xen_intr_port_to_isrc[isrc->xi_port] = isrc; mtx_unlock(&xen_intr_isrc_lock); @@ -450,13 +457,29 @@ /* ->xi_cookie is cleared by BIND_PARAMS() */ #ifdef SMP - if (isrc->xi_type == EVTCHN_TYPE_PORT) { + if (cpu > mp_maxid) { /* * By default all interrupts are assigned to vCPU#0 * unless specified otherwise, so shuffle them to balance * the interrupt load. */ - xen_intr_assign_cpu(&isrc->xi_intsrc, intr_next_cpu(0)); + cpu = intr_next_cpu(0); + } + + error = intr_event_bind(isrc->xi_intsrc.is_event, cpu); + if (error != 0) { /* *very* unlikely */ + xen_intr_release_isrc(isrc); + return (error); + } + + if (isrc->xi_cpu != cpu) { + /* + * Too early in the boot process for the generic interrupt + * code to perform the binding. Update our event channel + * masks manually so events can't fire on the wrong cpu + * during AP startup. + */ + xen_intr_assign_cpu(&isrc->xi_intsrc, cpu); } #endif @@ -1015,7 +1038,7 @@ * The Event Channel API didn't open this port, so it is not * responsible for closing it automatically on unbind. */ - struct xenisrc params = BIND_PARAMS(EVTCHN_TYPE_PORT, + struct xenisrc params = BIND_PARAMS(EVTCHN_TYPE_PORT, ~0U, .xi_close = 0, .xi_port = local_port, ); @@ -1030,7 +1053,7 @@ enum intr_type flags, xen_intr_handle_t *port_handlep) { struct xenisrc *isrc; - struct xenisrc params = BIND_PARAMS(EVTCHN_TYPE_PORT); + struct xenisrc params = BIND_PARAMS(EVTCHN_TYPE_PORT, ~0U); struct evtchn_alloc_unbound alloc_unbound; int error; @@ -1066,7 +1089,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 xenisrc params = BIND_PARAMS(EVTCHN_TYPE_PORT, ~0U); struct evtchn_bind_interdomain bind_interdomain; int error; @@ -1107,7 +1130,7 @@ { u_int vcpu_id = XEN_CPUID_TO_VCPUID(cpu); struct xenisrc *isrc; - struct xenisrc params = BIND_PARAMS(EVTCHN_TYPE_VIRQ, + struct xenisrc params = BIND_PARAMS(EVTCHN_TYPE_VIRQ, cpu, .xi_virq = virq, ); struct evtchn_bind_virq bind_virq = { .virq = virq, .vcpu = vcpu_id }; @@ -1127,33 +1150,14 @@ error = xen_intr_bind_isrc(&isrc, ¶ms, device_get_nameunit(dev), filter, handler, arg, flags, port_handlep); -#ifdef SMP - if (error == 0) - error = intr_event_bind(isrc->xi_intsrc.is_event, cpu); -#endif - if (error != 0) { evtchn_close_t close = { .port = bind_virq.port }; - if (isrc != NULL) - xen_intr_release_isrc(isrc); if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)) panic("EVTCHNOP_close failed"); return (error); } -#ifdef SMP - if (isrc->xi_cpu != cpu) { - /* - * Too early in the boot process for the generic interrupt - * code to perform the binding. Update our event channel - * masks manually so events can't fire on the wrong cpu - * during AP startup. - */ - xen_intr_assign_cpu(&isrc->xi_intsrc, cpu); - } -#endif - /* * The Event Channel API opened this port, so it is * responsible for closing it automatically on unbind. @@ -1170,7 +1174,7 @@ #ifdef SMP u_int vcpu_id = XEN_CPUID_TO_VCPUID(cpu); struct xenisrc *isrc; - struct xenisrc params = BIND_PARAMS(EVTCHN_TYPE_IPI); + struct xenisrc params = BIND_PARAMS(EVTCHN_TYPE_IPI, cpu); struct evtchn_bind_ipi bind_ipi = { .vcpu = vcpu_id }; /* Same size as the one used by intr_handler->ih_name. */ char name[MAXCOMLEN + 1]; @@ -1194,23 +1198,11 @@ if (error != 0) { evtchn_close_t close = { .port = bind_ipi.port }; - if (isrc != NULL) - xen_intr_release_isrc(isrc); if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)) panic("EVTCHNOP_close failed"); return (error); } - if (isrc->xi_cpu != cpu) { - /* - * Too early in the boot process for the generic interrupt - * code to perform the binding. Update our event channel - * masks manually so events can't fire on the wrong cpu - * during AP startup. - */ - xen_intr_assign_cpu(&isrc->xi_intsrc, cpu); - } - /* * The Event Channel API opened this port, so it is * responsible for closing it automatically on unbind.