Changeset View
Changeset View
Standalone View
Standalone View
sys/x86/xen/xen_intr.c
Show First 20 Lines • Show All 114 Lines • ▼ Show 20 Lines | |||||
#define XEN_INVALID_EVTCHN 0 /* Invalid event channel */ | #define XEN_INVALID_EVTCHN 0 /* Invalid event channel */ | ||||
#define is_valid_evtchn(x) ((x) != XEN_INVALID_EVTCHN) | #define is_valid_evtchn(x) ((x) != XEN_INVALID_EVTCHN) | ||||
struct xenisrc { | struct xenisrc { | ||||
struct intsrc xi_intsrc; | struct intsrc xi_intsrc; | ||||
enum evtchn_type xi_type; | enum evtchn_type xi_type; | ||||
int xi_cpu; /* VCPU for delivery. */ | u_int xi_cpu; /* VCPU for delivery. */ | ||||
int xi_vector; /* Global isrc vector number. */ | int xi_vector; /* Global isrc vector number. */ | ||||
evtchn_port_t xi_port; | evtchn_port_t xi_port; | ||||
int xi_virq; | u_int xi_virq; | ||||
void *xi_cookie; | void *xi_cookie; | ||||
u_int xi_close:1; /* close on unbind? */ | u_int xi_close:1; /* close on unbind? */ | ||||
u_int xi_masked:1; | u_int xi_masked:1; | ||||
volatile u_int xi_refcount; | volatile u_int xi_refcount; | ||||
}; | }; | ||||
static void xen_intr_suspend(struct pic *); | static void xen_intr_suspend(struct pic *); | ||||
static void xen_intr_resume(struct pic *, bool suspend_cancelled); | static void xen_intr_resume(struct pic *, bool suspend_cancelled); | ||||
▲ Show 20 Lines • Show All 425 Lines • ▼ Show 20 Lines | do { | ||||
synch_clear_bit(port, &s->evtchn_pending[0]); | synch_clear_bit(port, &s->evtchn_pending[0]); | ||||
isrc = xen_intr_port_to_isrc[port]; | isrc = xen_intr_port_to_isrc[port]; | ||||
if (__predict_false(isrc == NULL)) | if (__predict_false(isrc == NULL)) | ||||
continue; | continue; | ||||
/* Make sure we are firing on the right vCPU */ | /* Make sure we are firing on the right vCPU */ | ||||
KASSERT((isrc->xi_cpu == PCPU_GET(cpuid)), | KASSERT((isrc->xi_cpu == PCPU_GET(cpuid)), | ||||
("Received unexpected event on vCPU#%d, event bound to vCPU#%d", | ("Received unexpected event on vCPU#%d, event bound to vCPU#%u", | ||||
PCPU_GET(cpuid), isrc->xi_cpu)); | PCPU_GET(cpuid), isrc->xi_cpu)); | ||||
intr_execute_handlers(&isrc->xi_intsrc, trap_frame); | intr_execute_handlers(&isrc->xi_intsrc, trap_frame); | ||||
/* | /* | ||||
* If this is the final port processed, | * If this is the final port processed, | ||||
* we'll pick up here+1 next time. | * we'll pick up here+1 next time. | ||||
*/ | */ | ||||
Show All 36 Lines | xen_intr_init(void *dummy __unused) | ||||
*/ | */ | ||||
CPU_FOREACH(i) { | CPU_FOREACH(i) { | ||||
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)); | ||||
} | } | ||||
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], ~0UL); | ||||
intr_register_pic(&xen_intr_pic); | intr_register_pic(&xen_intr_pic); | ||||
if (bootverbose) | if (bootverbose) | ||||
printf("Xen interrupt system initialized\n"); | printf("Xen interrupt system initialized\n"); | ||||
return (0); | return (0); | ||||
} | } | ||||
Show All 34 Lines | |||||
xen_intr_suspend(struct pic *unused) | xen_intr_suspend(struct pic *unused) | ||||
{ | { | ||||
} | } | ||||
static void | static void | ||||
xen_rebind_ipi(struct xenisrc *isrc) | xen_rebind_ipi(struct xenisrc *isrc) | ||||
{ | { | ||||
#ifdef SMP | #ifdef SMP | ||||
int cpu = isrc->xi_cpu; | u_int cpu = isrc->xi_cpu; | ||||
int vcpu_id = pcpu_find(cpu)->pc_vcpu_id; | u_int vcpu_id = pcpu_find(cpu)->pc_vcpu_id; | ||||
int error; | int error; | ||||
struct evtchn_bind_ipi bind_ipi = { .vcpu = vcpu_id }; | struct evtchn_bind_ipi bind_ipi = { .vcpu = vcpu_id }; | ||||
error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi, | error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi, | ||||
&bind_ipi); | &bind_ipi); | ||||
if (error != 0) | if (error != 0) | ||||
panic("unable to rebind xen IPI: %d", error); | panic("unable to rebind xen IPI: %d", error); | ||||
Show All 11 Lines | |||||
#else | #else | ||||
panic("Resume IPI event channel on UP"); | panic("Resume IPI event channel on UP"); | ||||
#endif | #endif | ||||
} | } | ||||
static void | static void | ||||
xen_rebind_virq(struct xenisrc *isrc) | xen_rebind_virq(struct xenisrc *isrc) | ||||
{ | { | ||||
int cpu = isrc->xi_cpu; | u_int cpu = isrc->xi_cpu; | ||||
int vcpu_id = pcpu_find(cpu)->pc_vcpu_id; | u_int vcpu_id = pcpu_find(cpu)->pc_vcpu_id; | ||||
int error; | int error; | ||||
struct evtchn_bind_virq bind_virq = { .virq = isrc->xi_virq, | struct evtchn_bind_virq bind_virq = { .virq = isrc->xi_virq, | ||||
.vcpu = vcpu_id }; | .vcpu = vcpu_id }; | ||||
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); | ||||
Show All 33 Lines | CPU_FOREACH(i) { | ||||
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], ~0UL); | ||||
/* Remove port -> isrc mappings */ | /* Remove port -> isrc mappings */ | ||||
memset(xen_intr_port_to_isrc, 0, sizeof(xen_intr_port_to_isrc)); | memset(xen_intr_port_to_isrc, 0, sizeof(xen_intr_port_to_isrc)); | ||||
/* Free unused isrcs and rebind VIRQs and IPIs */ | /* Free unused isrcs and rebind VIRQs and IPIs */ | ||||
for (isrc_idx = 0; isrc_idx < xen_intr_auto_vector_count; isrc_idx++) { | for (isrc_idx = 0; isrc_idx < xen_intr_auto_vector_count; isrc_idx++) { | ||||
u_int vector; | u_int vector; | ||||
▲ Show 20 Lines • Show All 313 Lines • ▼ Show 20 Lines | xen_intr_bind_remote_port(device_t dev, u_int remote_domain, | ||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
xen_intr_bind_virq(device_t dev, u_int virq, u_int cpu, | xen_intr_bind_virq(device_t dev, u_int virq, u_int cpu, | ||||
driver_filter_t filter, driver_intr_t handler, void *arg, | driver_filter_t filter, driver_intr_t handler, void *arg, | ||||
enum intr_type flags, xen_intr_handle_t *port_handlep) | enum intr_type flags, xen_intr_handle_t *port_handlep) | ||||
{ | { | ||||
int vcpu_id = pcpu_find(cpu)->pc_vcpu_id; | u_int vcpu_id = pcpu_find(cpu)->pc_vcpu_id; | ||||
struct xenisrc *isrc; | struct xenisrc *isrc; | ||||
struct evtchn_bind_virq bind_virq = { .virq = virq, .vcpu = vcpu_id }; | struct evtchn_bind_virq bind_virq = { .virq = virq, .vcpu = vcpu_id }; | ||||
int error; | int error; | ||||
isrc = NULL; | isrc = NULL; | ||||
error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, &bind_virq); | error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, &bind_virq); | ||||
if (error != 0) { | if (error != 0) { | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | #endif | ||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
xen_intr_alloc_and_bind_ipi(u_int cpu, driver_filter_t filter, | xen_intr_alloc_and_bind_ipi(u_int cpu, driver_filter_t filter, | ||||
enum intr_type flags, xen_intr_handle_t *port_handlep) | enum intr_type flags, xen_intr_handle_t *port_handlep) | ||||
{ | { | ||||
#ifdef SMP | #ifdef SMP | ||||
int vcpu_id = pcpu_find(cpu)->pc_vcpu_id; | u_int vcpu_id = pcpu_find(cpu)->pc_vcpu_id; | ||||
struct xenisrc *isrc; | struct xenisrc *isrc; | ||||
struct evtchn_bind_ipi bind_ipi = { .vcpu = vcpu_id }; | struct evtchn_bind_ipi bind_ipi = { .vcpu = vcpu_id }; | ||||
/* Same size as the one used by intr_handler->ih_name. */ | /* Same size as the one used by intr_handler->ih_name. */ | ||||
char name[MAXCOMLEN + 1]; | char name[MAXCOMLEN + 1]; | ||||
int error; | int error; | ||||
isrc = NULL; | isrc = NULL; | ||||
error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi, &bind_ipi); | error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi, &bind_ipi); | ||||
▲ Show 20 Lines • Show All 171 Lines • ▼ Show 20 Lines | xen_intr_print_type(enum evtchn_type type) | ||||
return (evtchn_type_to_string[type]); | return (evtchn_type_to_string[type]); | ||||
} | } | ||||
static void | static void | ||||
xen_intr_dump_port(struct xenisrc *isrc) | xen_intr_dump_port(struct xenisrc *isrc) | ||||
{ | { | ||||
struct xen_intr_pcpu_data *pcpu; | struct xen_intr_pcpu_data *pcpu; | ||||
shared_info_t *s = HYPERVISOR_shared_info; | shared_info_t *s = HYPERVISOR_shared_info; | ||||
int i; | u_int i; | ||||
db_printf("Port %d Type: %s\n", | db_printf("Port %d Type: %s\n", | ||||
isrc->xi_port, xen_intr_print_type(isrc->xi_type)); | isrc->xi_port, xen_intr_print_type(isrc->xi_type)); | ||||
if (isrc->xi_type == EVTCHN_TYPE_VIRQ) | if (isrc->xi_type == EVTCHN_TYPE_VIRQ) | ||||
db_printf("\tVirq: %d\n", isrc->xi_virq); | db_printf("\tVirq: %d\n", isrc->xi_virq); | ||||
db_printf("\tMasked: %d Pending: %d\n", | db_printf("\tMasked: %d Pending: %d\n", | ||||
!!xen_test_bit(isrc->xi_port, &s->evtchn_mask[0]), | !!xen_test_bit(isrc->xi_port, &s->evtchn_mask[0]), | ||||
!!xen_test_bit(isrc->xi_port, &s->evtchn_pending[0])); | !!xen_test_bit(isrc->xi_port, &s->evtchn_pending[0])); | ||||
db_printf("\tPer-CPU Masks: "); | db_printf("\tPer-CPU Masks: "); | ||||
CPU_FOREACH(i) { | CPU_FOREACH(i) { | ||||
pcpu = DPCPU_ID_PTR(i, xen_intr_pcpu); | pcpu = DPCPU_ID_PTR(i, xen_intr_pcpu); | ||||
db_printf("cpu#%d: %d ", i, | db_printf("cpu#%u: %d ", i, | ||||
!!xen_test_bit(isrc->xi_port, pcpu->evtchn_enabled)); | !!xen_test_bit(isrc->xi_port, pcpu->evtchn_enabled)); | ||||
} | } | ||||
db_printf("\n"); | db_printf("\n"); | ||||
} | } | ||||
DB_SHOW_COMMAND(xen_evtchn, db_show_xen_evtchn) | DB_SHOW_COMMAND(xen_evtchn, db_show_xen_evtchn) | ||||
{ | { | ||||
int i; | u_int i; | ||||
if (!xen_domain()) { | if (!xen_domain()) { | ||||
db_printf("Only available on Xen guests\n"); | db_printf("Only available on Xen guests\n"); | ||||
return; | return; | ||||
} | } | ||||
for (i = 0; i < NR_EVENT_CHANNELS; i++) { | for (i = 0; i < NR_EVENT_CHANNELS; i++) { | ||||
struct xenisrc *isrc; | struct xenisrc *isrc; | ||||
Show All 9 Lines |