Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/xen/bus/xen_intr.c
Show First 20 Lines • Show All 194 Lines • ▼ Show 20 Lines | |||||
* source object. | * source object. | ||||
* | * | ||||
* \param type Restrict the search to interrupt sources of the given | * \param type Restrict the search to interrupt sources of the given | ||||
* type. | * type. | ||||
* | * | ||||
* \return A pointer to a free Xen interrupt source object or NULL. | * \return A pointer to a free Xen interrupt source object or NULL. | ||||
*/ | */ | ||||
static struct xenisrc * | static struct xenisrc * | ||||
xen_intr_find_unused_isrc(enum evtchn_type type) | xen_intr_find_unused_isrc(void) | ||||
{ | { | ||||
int isrc_idx; | int isrc_idx; | ||||
KASSERT(mtx_owned(&xen_intr_isrc_lock), ("Evtchn isrc lock not held")); | KASSERT(mtx_owned(&xen_intr_isrc_lock), ("Evtchn isrc lock not held")); | ||||
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 ++) { | ||||
struct xenisrc *isrc; | struct xenisrc *isrc; | ||||
u_int vector; | u_int vector; | ||||
vector = first_evtchn_irq + isrc_idx; | vector = first_evtchn_irq + isrc_idx; | ||||
isrc = (struct xenisrc *)intr_lookup_source(vector); | isrc = (struct xenisrc *)intr_lookup_source(vector); | ||||
/* | /* | ||||
* Since intr_register_source() must be called while unlocked, | * Since intr_register_source() must be called while unlocked, | ||||
* isrc == NULL *will* occur, though very infrequently. | * isrc == NULL *will* occur, though very infrequently. | ||||
* | * | ||||
* This also allows a very small gap where a foreign intrusion | * This also allows a very small gap where a foreign intrusion | ||||
* into Xen's interrupt range could be examined by this test. | * into Xen's interrupt range could be examined by this test. | ||||
*/ | */ | ||||
if (__predict_true(isrc != NULL) && | if (__predict_true(isrc != NULL) && | ||||
__predict_true(isrc->xi_arch.intsrc.is_pic == &xen_intr_pic) && | __predict_true(isrc->xi_arch.intsrc.is_pic == &xen_intr_pic) && | ||||
isrc->xi_type == EVTCHN_TYPE_UNBOUND) { | isrc->xi_type == EVTCHN_TYPE_UNBOUND) { | ||||
KASSERT(!xen_arch_intr_has_handlers(isrc), | KASSERT(!xen_arch_intr_has_handlers(isrc), | ||||
("Free evtchn still has handlers")); | ("Free evtchn still has handlers")); | ||||
isrc->xi_type = type; | isrc->xi_type = EVTCHN_TYPE_COUNT; /* mark allocated */ | ||||
return (isrc); | return (isrc); | ||||
} | } | ||||
} | } | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
/** | /** | ||||
* Allocate a Xen interrupt source object. | * Allocate a Xen interrupt source object. | ||||
* | * | ||||
* \param type The type of interrupt source to create. | * \param type The type of interrupt source to create. | ||||
* | * | ||||
* \return A pointer to a newly allocated Xen interrupt source | * \return A pointer to a newly allocated Xen interrupt source | ||||
* object or NULL. | * object or NULL. | ||||
*/ | */ | ||||
static struct xenisrc * | static struct xenisrc * | ||||
xen_intr_alloc_isrc(enum evtchn_type type) | xen_intr_alloc_isrc(const struct xenisrc *const params) | ||||
{ | { | ||||
static int warned; | static int warned; | ||||
struct xenisrc *isrc; | struct xenisrc *isrc; | ||||
unsigned int vector; | unsigned int vector; | ||||
int error; | int error; | ||||
mtx_lock(&xen_intr_isrc_lock); | mtx_lock(&xen_intr_isrc_lock); | ||||
isrc = xen_intr_find_unused_isrc(type); | isrc = xen_intr_find_unused_isrc(); | ||||
if (isrc != NULL) { | if (isrc != NULL) { | ||||
mtx_unlock(&xen_intr_isrc_lock); | mtx_unlock(&xen_intr_isrc_lock); | ||||
return (isrc); | goto out; | ||||
} | } | ||||
if (xen_intr_auto_vector_count >= NR_EVENT_CHANNELS) { | if (xen_intr_auto_vector_count >= NR_EVENT_CHANNELS) { | ||||
if (!warned) { | if (!warned) { | ||||
warned = 1; | warned = 1; | ||||
printf("%s: Xen interrupts exhausted.\n", __func__); | printf("%s: Xen interrupts exhausted.\n", __func__); | ||||
} | } | ||||
mtx_unlock(&xen_intr_isrc_lock); | mtx_unlock(&xen_intr_isrc_lock); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
vector = first_evtchn_irq + xen_intr_auto_vector_count; | vector = first_evtchn_irq + xen_intr_auto_vector_count; | ||||
xen_intr_auto_vector_count++; | xen_intr_auto_vector_count++; | ||||
KASSERT((intr_lookup_source(vector) == NULL), | KASSERT((intr_lookup_source(vector) == NULL), | ||||
("Trying to use an already allocated vector")); | ("Trying to use an already allocated vector")); | ||||
mtx_unlock(&xen_intr_isrc_lock); | mtx_unlock(&xen_intr_isrc_lock); | ||||
isrc = malloc(sizeof(*isrc), M_XENINTR, M_WAITOK | M_ZERO); | isrc = malloc(sizeof(*isrc), M_XENINTR, M_WAITOK | M_ZERO); | ||||
isrc->xi_arch.intsrc.is_pic = &xen_intr_pic; | isrc->xi_arch.intsrc.is_pic = &xen_intr_pic; | ||||
isrc->xi_arch.vector = vector; | isrc->xi_arch.vector = vector; | ||||
isrc->xi_type = type; | isrc->xi_type = EVTCHN_TYPE_COUNT; /* mark allocated */ | ||||
error = intr_register_source(&isrc->xi_arch.intsrc); | error = intr_register_source(&isrc->xi_arch.intsrc); | ||||
if (error != 0) | if (error != 0) | ||||
panic("%s(): failed registering interrupt %u, error=%d\n", | panic("%s(): failed registering interrupt %u, error=%d\n", | ||||
__func__, vector, error); | __func__, vector, error); | ||||
out: ; | |||||
CTASSERT(offsetof(struct xenisrc, xi_arch) == 0); | |||||
memcpy(&isrc->xi_arch + 1, ¶ms->xi_arch + 1, | |||||
sizeof(struct xenisrc) - sizeof(xen_arch_isrc_t)); | |||||
return (isrc); | return (isrc); | ||||
} | } | ||||
/** | /** | ||||
* Attempt to free an active Xen interrupt source object. | * Attempt to free an active Xen interrupt source object. | ||||
* | * | ||||
* \param isrc The interrupt source object to release. | * \param isrc The interrupt source object to release. | ||||
* | * | ||||
Show All 23 Lines | if (isrc->xi_close != 0) { | ||||
panic("EVTCHNOP_close failed"); | panic("EVTCHNOP_close failed"); | ||||
} | } | ||||
xen_intr_port_to_isrc[isrc->xi_port] = NULL; | xen_intr_port_to_isrc[isrc->xi_port] = NULL; | ||||
} | } | ||||
isrc->xi_cpu = 0; | isrc->xi_cpu = 0; | ||||
isrc->xi_type = EVTCHN_TYPE_UNBOUND; | isrc->xi_type = EVTCHN_TYPE_UNBOUND; | ||||
isrc->xi_port = INVALID_EVTCHN; | isrc->xi_port = INVALID_EVTCHN; | ||||
isrc->xi_cookie = NULL; | |||||
mtx_unlock(&xen_intr_isrc_lock); | mtx_unlock(&xen_intr_isrc_lock); | ||||
return (0); | return (0); | ||||
} | } | ||||
/** | /** | ||||
* Associate an interrupt handler with an already allocated local Xen | * Associate an interrupt handler with an already allocated local Xen | ||||
* event channel port. | * event channel port. | ||||
* | * | ||||
* \param isrcp The returned Xen interrupt object associated with | * \param isrcp The returned Xen interrupt object associated with | ||||
* the specified local port. | * the specified local port. | ||||
* \param local_port The event channel to bind. | * \param params Template xenisrc which can be used to initialize most | ||||
* \param type The event channel type of local_port. | * xenisrc fields. Usually BIND_PARAMS() is used to | ||||
* initialize this. | |||||
* \param intr_owner The device making this bind request. | * \param intr_owner The device making this bind request. | ||||
* \param filter An interrupt filter handler. Specify NULL | * \param filter An interrupt filter handler. Specify NULL | ||||
* to always dispatch to the ithread handler. | * to always dispatch to the ithread handler. | ||||
* \param handler An interrupt ithread handler. Optional (can | * \param handler An interrupt ithread handler. Optional (can | ||||
* specify NULL) if all necessary event actions | * specify NULL) if all necessary event actions | ||||
* are performed by filter. | * are performed by filter. | ||||
* \param arg Argument to present to both filter and handler. | * \param arg Argument to present to both filter and handler. | ||||
* \param irqflags Interrupt handler flags. See sys/bus.h. | * \param irqflags Interrupt handler flags. See sys/bus.h. | ||||
* \param handlep Pointer to an opaque handle used to manage this | * \param handlep Pointer to an opaque handle used to manage this | ||||
* registration. | * registration. | ||||
* | * | ||||
* \returns 0 on success, otherwise an errno. | * \returns 0 on success, otherwise an errno. | ||||
*/ | */ | ||||
#define BIND_PARAMS(type, ...) \ | |||||
{ \ | |||||
.xi_type = (type), \ | |||||
.xi_cookie = NULL, \ | |||||
__VA_ARGS__ \ | |||||
} | |||||
static int | static int | ||||
xen_intr_bind_isrc(struct xenisrc **isrcp, evtchn_port_t local_port, | xen_intr_bind_isrc(struct xenisrc **isrcp, const struct xenisrc *params, | ||||
enum evtchn_type type, const char *intr_owner, driver_filter_t filter, | const char *intr_owner, driver_filter_t filter, driver_intr_t handler, | ||||
driver_intr_t handler, void *arg, enum intr_type flags, | void *arg, enum intr_type flags, 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); | return (EINVAL); | ||||
} | } | ||||
isrc = xen_intr_alloc_isrc(type); | isrc = xen_intr_alloc_isrc(params); | ||||
if (isrc == NULL) | if (isrc == NULL) | ||||
return (ENOSPC); | return (ENOSPC); | ||||
isrc->xi_port = local_port; | |||||
refcount_init(&isrc->xi_refcount, 1); | refcount_init(&isrc->xi_refcount, 1); | ||||
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; | ||||
mtx_unlock(&xen_intr_isrc_lock); | mtx_unlock(&xen_intr_isrc_lock); | ||||
/* Assign the opaque handler */ | /* Assign the opaque handler */ | ||||
*port_handlep = xen_intr_handle_from_isrc(isrc); | *port_handlep = xen_intr_handle_from_isrc(isrc); | ||||
/* ->xi_cookie is cleared in BIND_PARAMS() */ | |||||
#ifdef SMP | #ifdef SMP | ||||
if (type == EVTCHN_TYPE_PORT) { | if (isrc->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 | ||||
* the interrupt load. | * the interrupt load. | ||||
*/ | */ | ||||
xen_intr_assign_cpu(isrc, intr_next_cpu(0)); | xen_intr_assign_cpu(isrc, intr_next_cpu(0)); | ||||
} | } | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 449 Lines • ▼ Show 20 Lines | |||||
/*--------------------------- Public Functions -------------------------------*/ | /*--------------------------- Public Functions -------------------------------*/ | ||||
/*------- API comments for these methods can be found in xen/xenintr.h -------*/ | /*------- API comments for these methods can be found in xen/xenintr.h -------*/ | ||||
int | int | ||||
xen_intr_bind_local_port(device_t dev, evtchn_port_t local_port, | xen_intr_bind_local_port(device_t dev, evtchn_port_t local_port, | ||||
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; | ||||
int error; | struct xenisrc params = BIND_PARAMS(EVTCHN_TYPE_PORT, | ||||
.xi_port = local_port, | |||||
error = xen_intr_bind_isrc(&isrc, local_port, EVTCHN_TYPE_PORT, | |||||
device_get_nameunit(dev), filter, handler, arg, flags, | |||||
port_handlep); | |||||
if (error != 0) | |||||
return (error); | |||||
/* | /* | ||||
* The Event Channel API didn't open this port, so it is not | * The Event Channel API didn't open this port, so it is not | ||||
* responsible for closing it automatically on unbind. | * responsible for closing it automatically on unbind. | ||||
*/ | */ | ||||
isrc->xi_close = 0; | .xi_close = 0, | ||||
return (0); | ); | ||||
return (xen_intr_bind_isrc(&isrc, ¶ms, device_get_nameunit(dev), | |||||
filter, handler, arg, flags, port_handlep)); | |||||
} | } | ||||
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 = BIND_PARAMS(EVTCHN_TYPE_PORT); | |||||
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); | ||||
} | } | ||||
error = xen_intr_bind_isrc(&isrc, alloc_unbound.port, EVTCHN_TYPE_PORT, | params.xi_port = alloc_unbound.port; | ||||
device_get_nameunit(dev), filter, handler, arg, flags, | error = xen_intr_bind_isrc(&isrc, ¶ms, device_get_nameunit(dev), | ||||
port_handlep); | filter, handler, arg, flags, port_handlep); | ||||
if (error != 0) { | if (error != 0) { | ||||
evtchn_close_t close = { .port = alloc_unbound.port }; | evtchn_close_t close = { .port = params.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"); | ||||
return (error); | return (error); | ||||
} | } | ||||
isrc->xi_close = 1; | isrc->xi_close = 1; | ||||
return (0); | 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 = BIND_PARAMS(EVTCHN_TYPE_PORT); | |||||
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); | ||||
} | } | ||||
error = xen_intr_bind_isrc(&isrc, bind_interdomain.local_port, | params.xi_port = bind_interdomain.local_port; | ||||
EVTCHN_TYPE_PORT, device_get_nameunit(dev), filter, handler, arg, | error = xen_intr_bind_isrc(&isrc, ¶ms, device_get_nameunit(dev), | ||||
flags, port_handlep); | filter, handler, arg, flags, port_handlep); | ||||
if (error) { | if (error) { | ||||
evtchn_close_t close = { .port = bind_interdomain.local_port }; | evtchn_close_t close = { .port = params.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"); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* The Event Channel API opened this port, so it is | * The Event Channel API opened this port, so it is | ||||
* responsible for closing it automatically on unbind. | * responsible for closing it automatically on unbind. | ||||
*/ | */ | ||||
isrc->xi_close = 1; | isrc->xi_close = 1; | ||||
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) | ||||
{ | { | ||||
u_int vcpu_id = XEN_CPUID_TO_VCPUID(cpu); | u_int vcpu_id = XEN_CPUID_TO_VCPUID(cpu); | ||||
struct xenisrc *isrc; | struct xenisrc *isrc; | ||||
struct xenisrc params = BIND_PARAMS(EVTCHN_TYPE_VIRQ, | |||||
.xi_virq = virq, | |||||
); | |||||
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) { | ||||
/* | /* | ||||
* XXX Trap Hypercall error code Linuxisms in | * XXX Trap Hypercall error code Linuxisms in | ||||
* the HYPERCALL layer. | * the HYPERCALL layer. | ||||
*/ | */ | ||||
return (-error); | return (-error); | ||||
} | } | ||||
error = xen_intr_bind_isrc(&isrc, bind_virq.port, EVTCHN_TYPE_VIRQ, | params.xi_port = bind_virq.port; | ||||
device_get_nameunit(dev), filter, handler, arg, flags, | error = xen_intr_bind_isrc(&isrc, ¶ms, device_get_nameunit(dev), | ||||
port_handlep); | filter, handler, arg, flags, port_handlep); | ||||
#ifdef SMP | #ifdef SMP | ||||
if (error == 0) | if (error == 0) | ||||
error = xen_arch_intr_event_bind(isrc, cpu); | error = xen_arch_intr_event_bind(isrc, cpu); | ||||
#endif | #endif | ||||
if (error != 0) { | if (error != 0) { | ||||
evtchn_close_t close = { .port = bind_virq.port }; | evtchn_close_t close = { .port = params.xi_port }; | ||||
xen_intr_unbind(*port_handlep); | xen_intr_unbind(*port_handlep); | ||||
if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)) | if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)) | ||||
panic("EVTCHNOP_close failed"); | panic("EVTCHNOP_close failed"); | ||||
return (error); | return (error); | ||||
} | } | ||||
#ifdef SMP | #ifdef SMP | ||||
if (isrc->xi_cpu != cpu) { | if (isrc->xi_cpu != cpu) { | ||||
/* | /* | ||||
* Too early in the boot process for the generic interrupt | * Too early in the boot process for the generic interrupt | ||||
* code to perform the binding. Update our event channel | * code to perform the binding. Update our event channel | ||||
* masks manually so events can't fire on the wrong cpu | * masks manually so events can't fire on the wrong cpu | ||||
* during AP startup. | * during AP startup. | ||||
*/ | */ | ||||
xen_intr_assign_cpu(isrc, cpu); | xen_intr_assign_cpu(isrc, cpu); | ||||
} | } | ||||
#endif | #endif | ||||
/* | /* | ||||
* The Event Channel API opened this port, so it is | * The Event Channel API opened this port, so it is | ||||
* responsible for closing it automatically on unbind. | * responsible for closing it automatically on unbind. | ||||
*/ | */ | ||||
isrc->xi_close = 1; | isrc->xi_close = 1; | ||||
isrc->xi_virq = virq; | |||||
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 | ||||
u_int vcpu_id = XEN_CPUID_TO_VCPUID(cpu); | u_int vcpu_id = XEN_CPUID_TO_VCPUID(cpu); | ||||
struct xenisrc *isrc; | struct xenisrc *isrc; | ||||
struct xenisrc params = BIND_PARAMS(EVTCHN_TYPE_IPI); | |||||
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); | ||||
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_ipi.port; | |||||
snprintf(name, sizeof(name), "cpu%u", cpu); | snprintf(name, sizeof(name), "cpu%u", cpu); | ||||
error = xen_intr_bind_isrc(&isrc, bind_ipi.port, EVTCHN_TYPE_IPI, | error = xen_intr_bind_isrc(&isrc, ¶ms, name, filter, NULL, NULL, | ||||
name, filter, NULL, NULL, flags, port_handlep); | flags, port_handlep); | ||||
if (error != 0) { | if (error != 0) { | ||||
evtchn_close_t close = { .port = bind_ipi.port }; | evtchn_close_t close = { .port = params.xi_port }; | ||||
xen_intr_unbind(*port_handlep); | xen_intr_unbind(*port_handlep); | ||||
if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)) | if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)) | ||||
panic("EVTCHNOP_close failed"); | panic("EVTCHNOP_close failed"); | ||||
return (error); | return (error); | ||||
} | } | ||||
if (isrc->xi_cpu != cpu) { | if (isrc->xi_cpu != cpu) { | ||||
▲ Show 20 Lines • Show All 195 Lines • Show Last 20 Lines |