Changeset View
Changeset View
Standalone View
Standalone View
sys/x86/xen/xen_intr.c
Show First 20 Lines • Show All 723 Lines • ▼ Show 20 Lines | xen_rebind_virq(struct xenisrc *isrc) | ||||
error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, | error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, | ||||
&bind_virq); | &bind_virq); | ||||
if (error != 0) | if (error != 0) | ||||
panic("unable to rebind xen VIRQ#%d: %d", isrc->xi_virq, error); | panic("unable to rebind xen VIRQ#%d: %d", isrc->xi_virq, error); | ||||
isrc->xi_port = bind_virq.port; | isrc->xi_port = bind_virq.port; | ||||
} | } | ||||
static void | static struct xenisrc * | ||||
xen_intr_rebind_isrc(struct xenisrc *isrc) | xen_intr_rebind_isrc(struct xenisrc *isrc) | ||||
{ | { | ||||
#ifdef SMP | #ifdef SMP | ||||
u_int cpu = isrc->xi_cpu; | u_int cpu = isrc->xi_cpu; | ||||
int error; | int error; | ||||
#endif | #endif | ||||
struct xenisrc *prev; | |||||
switch (isrc->xi_type) { | switch (isrc->xi_type) { | ||||
case EVTCHN_TYPE_IPI: | case EVTCHN_TYPE_IPI: | ||||
xen_rebind_ipi(isrc); | xen_rebind_ipi(isrc); | ||||
break; | break; | ||||
case EVTCHN_TYPE_VIRQ: | case EVTCHN_TYPE_VIRQ: | ||||
xen_rebind_virq(isrc); | xen_rebind_virq(isrc); | ||||
break; | break; | ||||
default: | default: | ||||
return; | return (NULL); | ||||
} | } | ||||
prev = xen_intr_port_to_isrc[isrc->xi_port]; | |||||
xen_intr_port_to_isrc[isrc->xi_port] = isrc; | xen_intr_port_to_isrc[isrc->xi_port] = isrc; | ||||
#ifdef SMP | #ifdef SMP | ||||
isrc->xi_cpu = 0; | isrc->xi_cpu = 0; | ||||
error = xen_intr_assign_cpu(&isrc->xi_intsrc, | error = xen_intr_assign_cpu(&isrc->xi_intsrc, | ||||
cpu_apic_ids[cpu]); | cpu_apic_ids[cpu]); | ||||
if (error) | if (error) | ||||
panic("%s(): unable to rebind Xen channel %u to vCPU%u: %d", | panic("%s(): unable to rebind Xen channel %u to vCPU%u: %d", | ||||
__func__, isrc->xi_port, cpu, error); | __func__, isrc->xi_port, cpu, error); | ||||
#endif | #endif | ||||
evtchn_unmask_port(isrc->xi_port); | evtchn_unmask_port(isrc->xi_port); | ||||
return (prev); | |||||
} | } | ||||
/** | /** | ||||
* Return this PIC to service after being suspended. | * Return this PIC to service after being suspended. | ||||
*/ | */ | ||||
static void | static void | ||||
xen_intr_resume(struct pic *unused, bool suspend_cancelled) | xen_intr_resume(struct pic *unused, bool suspend_cancelled) | ||||
{ | { | ||||
shared_info_t *s = HYPERVISOR_shared_info; | shared_info_t *s = HYPERVISOR_shared_info; | ||||
struct xenisrc *isrc; | |||||
u_int isrc_idx; | u_int isrc_idx; | ||||
int i; | int i; | ||||
if (suspend_cancelled) | if (suspend_cancelled) | ||||
return; | return; | ||||
/* Reset the per-CPU masks */ | /* Reset the per-CPU masks */ | ||||
CPU_FOREACH(i) { | CPU_FOREACH(i) { | ||||
struct xen_intr_pcpu_data *pcpu; | struct xen_intr_pcpu_data *pcpu; | ||||
pcpu = DPCPU_ID_PTR(i, xen_intr_pcpu); | pcpu = DPCPU_ID_PTR(i, xen_intr_pcpu); | ||||
memset(pcpu->evtchn_enabled, i == 0 ? ~0 : 0, | memset(pcpu->evtchn_enabled, i == 0 ? ~0 : 0, | ||||
sizeof(pcpu->evtchn_enabled)); | sizeof(pcpu->evtchn_enabled)); | ||||
} | } | ||||
/* Mask all event channels. */ | /* Mask all event channels. */ | ||||
for (i = 0; i < nitems(s->evtchn_mask); i++) | for (i = 0; i < nitems(s->evtchn_mask); i++) | ||||
atomic_store_rel_long(&s->evtchn_mask[i], ~0); | atomic_store_rel_long(&s->evtchn_mask[i], ~0); | ||||
/* Remove port -> isrc mappings */ | /* Clear existing port mappings */ | ||||
memset(xen_intr_port_to_isrc, 0, sizeof(xen_intr_port_to_isrc)); | 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 = | |||||
INVALID_EVTCHN; | |||||
/* Free unused isrcs and rebind VIRQs and IPIs */ | /* Remap in-use isrcs, using xen_intr_port_to_isrc as listing */ | ||||
for (isrc_idx = 0; isrc_idx < xen_intr_auto_vector_count; isrc_idx++) { | for (isrc_idx = 0; isrc_idx < NR_EVENT_CHANNELS; ++isrc_idx) { | ||||
u_int vector; | struct xenisrc *cur = xen_intr_port_to_isrc[isrc_idx]; | ||||
vector = first_evtchn_irq + isrc_idx; | /* empty or entry already taken care of */ | ||||
isrc = (struct xenisrc *)intr_lookup_source(vector); | if (cur == NULL || cur->xi_port == isrc_idx) | ||||
if (isrc != NULL) { | continue; | ||||
isrc->xi_port = INVALID_EVTCHN; | |||||
xen_intr_rebind_isrc(isrc); | xen_intr_port_to_isrc[isrc_idx] = NULL; | ||||
} | |||||
do { | |||||
KASSERT(!is_valid_evtchn(cur->xi_port), | |||||
("%s(): Multiple channels on single intr?", | |||||
__func__)); | |||||
cur = xen_intr_rebind_isrc(cur); | |||||
} while (cur != NULL); | |||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Disable a Xen interrupt source. | * Disable a Xen interrupt source. | ||||
* | * | ||||
* \param isrc The interrupt source to disable. | * \param isrc The interrupt source to disable. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 586 Lines • Show Last 20 Lines |