Index: sys/xen/xen_intr.c =================================================================== --- sys/xen/xen_intr.c +++ sys/xen/xen_intr.c @@ -710,12 +710,13 @@ isrc->xi_port = bind_virq.port; } -static void +static struct xenisrc * xen_intr_rebind_isrc(struct xenisrc *isrc) { int cpu = isrc->xi_cpu; const char *errfmt; int error; + struct xenisrc *prev; switch (isrc->xi_type) { case EVTCHN_TYPE_IPI: @@ -727,9 +728,10 @@ errfmt = "%1$s: unable to bind xen VIRQ#%4$d to CPU#%2$d: %3$d"; 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 @@ -741,6 +743,8 @@ #endif evtchn_unmask_port(isrc->xi_port); + + return (prev); } /** @@ -750,7 +754,6 @@ xen_intr_resume(struct pic *unused, bool suspend_cancelled) { shared_info_t *s = HYPERVISOR_shared_info; - struct xenisrc *isrc; u_int isrc_idx; int i; @@ -770,17 +773,28 @@ for (i = 0; i < nitems(s->evtchn_mask); i++) atomic_store_rel_long(&s->evtchn_mask[i], ~0); - /* 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 = ~0; - /* 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) - 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); } }