Changeset View
Changeset View
Standalone View
Standalone View
sys/xen/xen_intr.c
Show First 20 Lines • Show All 332 Lines • ▼ Show 20 Lines | xen_intr_release_isrc(struct xenisrc *isrc) | ||||
/* Rebind port to CPU 0. */ | /* Rebind port to CPU 0. */ | ||||
evtchn_cpu_mask_port(isrc->xi_cpu, isrc->xi_port); | evtchn_cpu_mask_port(isrc->xi_cpu, isrc->xi_port); | ||||
evtchn_cpu_unmask_port(0, isrc->xi_port); | evtchn_cpu_unmask_port(0, isrc->xi_port); | ||||
if (isrc->xi_close != 0) { | if (isrc->xi_close != 0) { | ||||
struct evtchn_close close = { .port = isrc->xi_port }; | struct evtchn_close close = { .port = isrc->xi_port }; | ||||
if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)) | if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)) | ||||
panic("EVTCHNOP_close failed"); | panic("EVTCHNOP_close failed"); | ||||
isrc->xi_close = 0; /* mark as closed */ | |||||
} | } | ||||
xen_intr_port_to_isrc[isrc->xi_port] = NULL; | xen_intr_port_to_isrc[isrc->xi_port] = NULL; | ||||
/* not reachable from xen_intr_port_to_isrc[], therefore unlock */ | /* not reachable from xen_intr_port_to_isrc[], therefore unlock */ | ||||
mtx_unlock(&xen_intr_isrc_lock); | mtx_unlock(&xen_intr_isrc_lock); | ||||
isrc->xi_cpu = 0; | isrc->xi_cpu = 0; | ||||
isrc->xi_port = ~0; | isrc->xi_port = ~0; | ||||
Show All 32 Lines | xen_intr_bind_isrc(struct xenisrc **isrcp, const struct xenisrc *params, | ||||
xen_intr_handle_t *port_handlep) | xen_intr_handle_t *port_handlep) | ||||
{ | { | ||||
struct xenisrc *isrc; | struct xenisrc *isrc; | ||||
int error; | int error; | ||||
*isrcp = NULL; | *isrcp = NULL; | ||||
if (port_handlep == NULL) { | if (port_handlep == NULL) { | ||||
printf("%s: %s: Bad event handle\n", intr_owner, __func__); | printf("%s: %s: Bad event handle\n", intr_owner, __func__); | ||||
return (EINVAL); | error = EINVAL; | ||||
goto fail; | |||||
} | } | ||||
isrc = xen_intr_alloc_isrc(params); | isrc = xen_intr_alloc_isrc(params); | ||||
if (isrc == NULL) | if (isrc == NULL) { | ||||
return (ENOSPC); | error = ENOSPC; | ||||
goto fail; | |||||
} | |||||
mtx_lock(&xen_intr_isrc_lock); | mtx_lock(&xen_intr_isrc_lock); | ||||
xen_intr_port_to_isrc[isrc->xi_port] = isrc; | xen_intr_port_to_isrc[isrc->xi_port] = isrc; | ||||
refcount_init(&isrc->xi_refcount, 1); | refcount_init(&isrc->xi_refcount, 1); | ||||
mtx_unlock(&xen_intr_isrc_lock); | mtx_unlock(&xen_intr_isrc_lock); | ||||
/* Now owned by isrc structure */ | |||||
params = isrc; | |||||
/* Assign the opaque handler */ | /* Assign the opaque handler */ | ||||
*port_handlep = xen_intr_handle_from_isrc(isrc); | *port_handlep = xen_intr_handle_from_isrc(isrc); | ||||
#ifdef SMP | #ifdef SMP | ||||
if (params->xi_type == EVTCHN_TYPE_PORT) { | if (params->xi_type == EVTCHN_TYPE_PORT) { | ||||
/* | /* | ||||
* By default all interrupts are assigned to vCPU#0 | * By default all interrupts are assigned to vCPU#0 | ||||
* unless specified otherwise, so shuffle them to balance | * unless specified otherwise, so shuffle them to balance | ||||
Show All 16 Lines | #endif | ||||
error = xen_intr_add_handler(intr_owner, filter, handler, arg, flags, | error = xen_intr_add_handler(intr_owner, filter, handler, arg, flags, | ||||
*port_handlep); | *port_handlep); | ||||
if (error != 0) { | if (error != 0) { | ||||
xen_intr_release_isrc(isrc); | xen_intr_release_isrc(isrc); | ||||
return (error); | return (error); | ||||
} | } | ||||
*isrcp = isrc; | *isrcp = isrc; | ||||
return (0); | return (0); | ||||
fail: | |||||
if (params->xi_close) { | |||||
evtchn_close_t close = { .port = params->xi_port }; | |||||
if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)) | |||||
panic("EVTCHNOP_close failed"); | |||||
/* params->xi_close = 0; ** mark as closed */ | |||||
} | } | ||||
return (error); | |||||
} | |||||
/** | /** | ||||
* Determine the event channel ports at the given section of the | * Determine the event channel ports at the given section of the | ||||
* event port bitmap which have pending events for the given cpu. | * event port bitmap which have pending events for the given cpu. | ||||
* | * | ||||
* \param pcpu The Xen interrupt pcpu data for the cpu being querried. | * \param pcpu The Xen interrupt pcpu data for the cpu being querried. | ||||
* \param sh The Xen shared info area. | * \param sh The Xen shared info area. | ||||
* \param idx The index of the section of the event channel bitmap to | * \param idx The index of the section of the event channel bitmap to | ||||
▲ Show 20 Lines • Show All 496 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
int | int | ||||
xen_intr_alloc_and_bind_local_port(device_t dev, u_int remote_domain, | xen_intr_alloc_and_bind_local_port(device_t dev, u_int remote_domain, | ||||
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) | ||||
{ | { | ||||
struct xenisrc *isrc; | struct xenisrc *isrc; | ||||
struct xenisrc params = { .xi_type = EVTCHN_TYPE_PORT, }; | struct xenisrc params = { .xi_type = EVTCHN_TYPE_PORT, .xi_close = 1, }; | ||||
struct evtchn_alloc_unbound alloc_unbound; | struct evtchn_alloc_unbound alloc_unbound; | ||||
int error; | int error; | ||||
alloc_unbound.dom = DOMID_SELF; | alloc_unbound.dom = DOMID_SELF; | ||||
alloc_unbound.remote_dom = remote_domain; | alloc_unbound.remote_dom = remote_domain; | ||||
error = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, | error = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, | ||||
&alloc_unbound); | &alloc_unbound); | ||||
if (error != 0) { | if (error != 0) { | ||||
/* | /* | ||||
* XXX Trap Hypercall error code Linuxisms in | * XXX Trap Hypercall error code Linuxisms in | ||||
* the HYPERCALL layer. | * the HYPERCALL layer. | ||||
*/ | */ | ||||
return (-error); | return (-error); | ||||
} | } | ||||
params.xi_port = alloc_unbound.port; | params.xi_port = alloc_unbound.port; | ||||
error = xen_intr_bind_isrc(&isrc, ¶ms, | return (xen_intr_bind_isrc(&isrc, ¶ms, | ||||
device_get_nameunit(dev), filter, handler, arg, flags, | device_get_nameunit(dev), filter, handler, arg, flags, | ||||
port_handlep); | port_handlep)); | ||||
if (error != 0) { | |||||
evtchn_close_t close = { .port = alloc_unbound.port }; | |||||
if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)) | |||||
panic("EVTCHNOP_close failed"); | |||||
return (error); | |||||
} | } | ||||
isrc->xi_close = 1; | |||||
return (0); | |||||
} | |||||
int | int | ||||
xen_intr_bind_remote_port(device_t dev, u_int remote_domain, | xen_intr_bind_remote_port(device_t dev, u_int remote_domain, | ||||
u_int remote_port, driver_filter_t filter, driver_intr_t handler, | u_int remote_port, driver_filter_t filter, driver_intr_t handler, | ||||
void *arg, enum intr_type flags, xen_intr_handle_t *port_handlep) | void *arg, enum intr_type flags, xen_intr_handle_t *port_handlep) | ||||
{ | { | ||||
struct xenisrc *isrc; | struct xenisrc *isrc; | ||||
struct xenisrc params = { | struct xenisrc params = { | ||||
.xi_type = EVTCHN_TYPE_PORT, | .xi_type = EVTCHN_TYPE_PORT, | ||||
/* | |||||
* The Event Channel API opened this port, so it is | |||||
* responsible for closing it automatically on unbind. | |||||
*/ | |||||
.xi_close = 1, | |||||
}; | }; | ||||
struct evtchn_bind_interdomain bind_interdomain; | struct evtchn_bind_interdomain bind_interdomain; | ||||
int error; | int error; | ||||
bind_interdomain.remote_dom = remote_domain; | bind_interdomain.remote_dom = remote_domain; | ||||
bind_interdomain.remote_port = remote_port; | bind_interdomain.remote_port = remote_port; | ||||
error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain, | error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain, | ||||
&bind_interdomain); | &bind_interdomain); | ||||
if (error != 0) { | if (error != 0) { | ||||
/* | /* | ||||
* XXX Trap Hypercall error code Linuxisms in | * XXX Trap Hypercall error code Linuxisms in | ||||
* the HYPERCALL layer. | * the HYPERCALL layer. | ||||
*/ | */ | ||||
return (-error); | return (-error); | ||||
} | } | ||||
params.xi_port = bind_interdomain.local_port; | params.xi_port = bind_interdomain.local_port; | ||||
error = xen_intr_bind_isrc(&isrc, ¶ms, | return (xen_intr_bind_isrc(&isrc, ¶ms, | ||||
device_get_nameunit(dev), filter, handler, arg, | device_get_nameunit(dev), filter, handler, arg, | ||||
flags, port_handlep); | flags, port_handlep)); | ||||
if (error) { | |||||
evtchn_close_t close = { .port = bind_interdomain.local_port }; | |||||
if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)) | |||||
panic("EVTCHNOP_close failed"); | |||||
return (error); | |||||
} | |||||
/* | |||||
* The Event Channel API opened this port, so it is | |||||
* responsible for closing it automatically on unbind. | |||||
*/ | |||||
isrc->xi_close = 1; | |||||
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_ID_GET(cpu); | int vcpu_id = PCPU_ID_GET(cpu); | ||||
▲ Show 20 Lines • Show All 297 Lines • Show Last 20 Lines |