Index: sys/xen/xen_intr.c =================================================================== --- sys/xen/xen_intr.c +++ sys/xen/xen_intr.c @@ -393,6 +393,9 @@ { struct xenisrc *isrc; int error; +#ifdef SMP + u_int cpu; +#endif *isrcp = NULL; if (port_handlep == NULL) { @@ -404,6 +407,9 @@ if (isrc == NULL) return (ENOSPC); refcount_init(&isrc->xi_refcount, 1); +#ifdef SMP + cpu = isrc->xi_cpu; +#endif isrc->xi_cpu = 0; /* initialize to the likely correct value */ mtx_lock(&xen_intr_isrc_lock); if (__predict_false(xen_intr_port_to_isrc[isrc->xi_port] != NULL)) { @@ -417,13 +423,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 @@ -944,6 +966,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 @@ -964,6 +987,7 @@ struct xenisrc *isrc; struct xenisrc params = { .xi_type = EVTCHN_TYPE_PORT, + .xi_cpu = ~0U, }; struct evtchn_alloc_unbound alloc_unbound; int error; @@ -1002,6 +1026,7 @@ struct xenisrc *isrc; struct xenisrc params = { .xi_type = EVTCHN_TYPE_PORT, + .xi_cpu = ~0U, }; struct evtchn_bind_interdomain bind_interdomain; int error; @@ -1045,6 +1070,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 }; @@ -1064,11 +1090,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 }; @@ -1078,18 +1099,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. @@ -1108,6 +1117,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. */ @@ -1138,16 +1148,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.