Index: sys/x86/xen/xen_intr.c =================================================================== --- sys/x86/xen/xen_intr.c +++ sys/x86/xen/xen_intr.c @@ -733,7 +733,7 @@ isrc->xi_port = bind_virq.port; } -static void +static struct xenisrc * xen_intr_rebind_isrc(struct xenisrc *isrc) { #ifdef SMP @@ -741,6 +741,7 @@ const char *errfmt; int error; #endif + struct xenisrc *prev; switch (isrc->xi_type) { case EVTCHN_TYPE_IPI: @@ -756,9 +757,10 @@ #endif break; default: - return; + return (NULL); } + prev = xen_intr_port_to_isrc[isrc->xi_port]; xen_intr_port_to_isrc[isrc->xi_port] = isrc; #ifdef SMP @@ -770,6 +772,8 @@ #endif evtchn_unmask_port(isrc->xi_port); + + return (prev); } /** @@ -779,7 +783,6 @@ xen_intr_resume(struct pic *unused, bool suspend_cancelled) { shared_info_t *s = HYPERVISOR_shared_info; - struct xenisrc *isrc; u_int isrc_idx; u_int i; @@ -799,19 +802,28 @@ for (i = 0; i < nitems(s->evtchn_mask); i++) atomic_store_rel_long(&s->evtchn_mask[i], ~0UL); - /* Remove port -> isrc mappings */ - memset(xen_intr_port_to_isrc, 0, sizeof(xen_intr_port_to_isrc)); + /* Clear existing port mappings */ + for (isrc_idx = 0; isrc_idx < NR_EVENT_CHANNELS; ++isrc_idx) + if (xen_intr_port_to_isrc[isrc_idx] != NULL) + xen_intr_port_to_isrc[isrc_idx]->xi_port = ~0U; - /* Free unused isrcs and rebind VIRQs and IPIs */ - for (isrc_idx = 0; isrc_idx < xen_intr_auto_vector_count; isrc_idx++) { - u_int vector; + /* Remap in-use isrcs, using xen_intr_port_to_isrc as listing */ + for (isrc_idx = 0; isrc_idx < NR_EVENT_CHANNELS; ++isrc_idx) { + struct xenisrc *cur = xen_intr_port_to_isrc[isrc_idx]; - vector = first_evtchn_irq + isrc_idx; - isrc = (struct xenisrc *)intr_lookup_source(vector); - if (isrc != NULL) { - isrc->xi_port = ~0; - xen_intr_rebind_isrc(isrc); - } + /* empty or entry already taken care of */ + if (cur == NULL || cur->xi_port == isrc_idx) + continue; + + xen_intr_port_to_isrc[isrc_idx] = NULL; + + do { + KASSERT(cur->xi_port >= NR_EVENT_CHANNELS, + ("%s(): Multiple channels on single intr?", + __func__)); + + cur = xen_intr_rebind_isrc(cur); + } while (cur != NULL); } }