Index: sys/xen/xen_intr.c =================================================================== --- sys/xen/xen_intr.c +++ sys/xen/xen_intr.c @@ -388,6 +388,7 @@ void *arg, enum intr_type flags, xen_intr_handle_t *port_handlep) { struct xenisrc *isrc; + u_int cpu; int error; *isrcp = NULL; @@ -399,11 +400,13 @@ isrc = xen_intr_alloc_isrc(params); if (isrc == NULL) return (ENOSPC); + cpu = isrc->xi_cpu; mtx_lock(&xen_intr_isrc_lock); if (xen_intr_port_to_isrc[isrc->xi_port] != NULL) { xen_intr_port_to_isrc[isrc->xi_port]->xi_port = ~0U; isrc->xi_cpu = xen_intr_port_to_isrc[isrc->xi_port]->xi_cpu; - } + } else + isrc->xi_cpu = 0; xen_intr_port_to_isrc[isrc->xi_port] = isrc; refcount_init(&isrc->xi_refcount, 1); mtx_unlock(&xen_intr_isrc_lock); @@ -412,13 +415,29 @@ *port_handlep = xen_intr_handle_from_isrc(isrc); #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, intr_next_cpu(0)); + cpu = intr_next_cpu(0); + } + + error = xen_arch_intr_event_bind(isrc, 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, cpu); } #endif @@ -930,6 +949,7 @@ struct xenisrc *isrc; struct xenisrc params = { .xi_type = EVTCHN_TYPE_PORT, + .xi_cpu = ~0U, .xi_port = local_port, /* * The Event Channel API didn't open this port, so it is not @@ -950,6 +970,7 @@ struct xenisrc *isrc; struct xenisrc params = { .xi_type = EVTCHN_TYPE_PORT, + .xi_cpu = ~0U, }; struct evtchn_alloc_unbound alloc_unbound; int error; @@ -988,6 +1009,7 @@ struct xenisrc *isrc; struct xenisrc params = { .xi_type = EVTCHN_TYPE_PORT, + .xi_cpu = ~0U, }; struct evtchn_bind_interdomain bind_interdomain; int error; @@ -1031,6 +1053,7 @@ struct xenisrc *isrc; struct xenisrc params = { .xi_type = EVTCHN_TYPE_VIRQ, + .xi_cpu = cpu, .xi_virq = virq, }; struct evtchn_bind_virq bind_virq = { .virq = virq, .vcpu = vcpu_id }; @@ -1050,11 +1073,6 @@ error = xen_intr_bind_isrc(&isrc, ¶ms, device_get_nameunit(dev), filter, handler, arg, flags, port_handlep); -#ifdef SMP - if (error == 0) - error = xen_arch_intr_event_bind(isrc, cpu); -#endif - if (error != 0) { evtchn_close_t close = { .port = params.xi_port }; @@ -1064,18 +1082,6 @@ 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, cpu); - } -#endif - /* * The Event Channel API opened this port, so it is * responsible for closing it automatically on unbind. @@ -1094,6 +1100,7 @@ struct xenisrc *isrc; struct xenisrc params = { .xi_type = EVTCHN_TYPE_IPI, + .xi_cpu = cpu, }; struct evtchn_bind_ipi bind_ipi = { .vcpu = vcpu_id }; /* Same size as the one used by intr_handler->ih_name. */ @@ -1124,16 +1131,6 @@ 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, cpu); - } - /* * The Event Channel API opened this port, so it is * responsible for closing it automatically on unbind.