Changeset View
Changeset View
Standalone View
Standalone View
sys/x86/xen/xen_intr.c
Show First 20 Lines • Show All 194 Lines • ▼ Show 20 Lines | ||||||||||
static struct mtx xen_intr_isrc_lock; | static struct mtx xen_intr_isrc_lock; | |||||||||
static u_int xen_intr_auto_vector_count; | static u_int xen_intr_auto_vector_count; | |||||||||
static struct xenisrc *xen_intr_port_to_isrc[NR_EVENT_CHANNELS]; | static struct xenisrc *xen_intr_port_to_isrc[NR_EVENT_CHANNELS]; | |||||||||
static u_long *xen_intr_pirq_eoi_map; | static u_long *xen_intr_pirq_eoi_map; | |||||||||
static boolean_t xen_intr_pirq_eoi_map_enabled; | static boolean_t xen_intr_pirq_eoi_map_enabled; | |||||||||
/*------------------------- Private Functions --------------------------------*/ | /*------------------------- Private Functions --------------------------------*/ | |||||||||
/** | /** | |||||||||
* Retrieve a handle for a Xen interrupt source. | ||||||||||
* | ||||||||||
* \param isrc A valid Xen interrupt source structure. | ||||||||||
* | ||||||||||
* \returns A handle suitable for use with xen_intr_isrc_from_handle() | ||||||||||
* to retrieve the original Xen interrupt source structure. | ||||||||||
*/ | ||||||||||
static __inline xen_intr_handle_t | ||||||||||
mhorne: Since this is just a type cast, the helpers can be marked `__inline` or converted to macros. | ||||||||||
Not Done Inline ActionsAny reason to use __inline instead of the C99 keyword inline? I can fix while committing if there's no specific reason to use __inline. royger: Any reason to use `__inline` instead of the C99 keyword `inline`?
I can fix while committing… | ||||||||||
xen_intr_handle_from_isrc(struct xenisrc *isrc) | ||||||||||
{ | ||||||||||
return (isrc); | ||||||||||
} | ||||||||||
/** | ||||||||||
* Lookup a Xen interrupt source object given an interrupt binding handle. | ||||||||||
* | ||||||||||
* \param handle A handle initialized by a previous call to | ||||||||||
* xen_intr_bind_isrc(). | ||||||||||
* | ||||||||||
* \returns A pointer to the Xen interrupt source object associated | ||||||||||
* with the given interrupt handle. NULL if no association | ||||||||||
* currently exists. | ||||||||||
*/ | ||||||||||
static __inline struct xenisrc * | ||||||||||
Not Done Inline Actions
mhorne: | ||||||||||
xen_intr_isrc_from_handle(xen_intr_handle_t handle) | ||||||||||
{ | ||||||||||
return ((struct xenisrc *)handle); | ||||||||||
} | ||||||||||
/** | ||||||||||
* Disable signal delivery for an event channel port on the | * Disable signal delivery for an event channel port on the | |||||||||
* specified CPU. | * specified CPU. | |||||||||
* | * | |||||||||
* \param port The event channel port to mask. | * \param port The event channel port to mask. | |||||||||
* | * | |||||||||
* This API is used to manage the port<=>CPU binding of event | * This API is used to manage the port<=>CPU binding of event | |||||||||
* channel handlers. | * channel handlers. | |||||||||
* | * | |||||||||
▲ Show 20 Lines • Show All 210 Lines • ▼ Show 20 Lines | if (isrc == NULL) { | |||||||||
return (ENOSPC); | return (ENOSPC); | |||||||||
} | } | |||||||||
} | } | |||||||||
isrc->xi_port = local_port; | isrc->xi_port = local_port; | |||||||||
xen_intr_port_to_isrc[local_port] = isrc; | xen_intr_port_to_isrc[local_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); | |||||||||
/* Assign the opaque handler (the event channel port) */ | /* Assign the opaque handler */ | |||||||||
*port_handlep = &isrc->xi_vector; | *port_handlep = xen_intr_handle_from_isrc(isrc); | |||||||||
#ifdef SMP | #ifdef SMP | |||||||||
if (type == EVTCHN_TYPE_PORT) { | if (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. | |||||||||
*/ | */ | |||||||||
Show All 17 Lines | 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); | |||||||||
} | } | |||||||||
/** | /** | |||||||||
* Lookup a Xen interrupt source object given an interrupt binding handle. | ||||||||||
* | ||||||||||
* \param handle A handle initialized by a previous call to | ||||||||||
* xen_intr_bind_isrc(). | ||||||||||
* | ||||||||||
* \returns A pointer to the Xen interrupt source object associated | ||||||||||
* with the given interrupt handle. NULL if no association | ||||||||||
* currently exists. | ||||||||||
*/ | ||||||||||
static struct xenisrc * | ||||||||||
xen_intr_isrc(xen_intr_handle_t handle) | ||||||||||
{ | ||||||||||
int vector; | ||||||||||
if (handle == NULL) | ||||||||||
return (NULL); | ||||||||||
vector = *(int *)handle; | ||||||||||
KASSERT(vector >= first_evtchn_irq && | ||||||||||
vector < (first_evtchn_irq + xen_intr_auto_vector_count), | ||||||||||
("Xen interrupt vector is out of range")); | ||||||||||
return ((struct xenisrc *)intr_lookup_source(vector)); | ||||||||||
} | ||||||||||
/** | ||||||||||
* 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 | |||||||||
* inspect. | * inspect. | |||||||||
* | * | |||||||||
▲ Show 20 Lines • Show All 1,010 Lines • ▼ Show 20 Lines | ||||||||||
int | int | |||||||||
xen_intr_describe(xen_intr_handle_t port_handle, const char *fmt, ...) | xen_intr_describe(xen_intr_handle_t port_handle, const char *fmt, ...) | |||||||||
{ | { | |||||||||
char descr[MAXCOMLEN + 1]; | char descr[MAXCOMLEN + 1]; | |||||||||
struct xenisrc *isrc; | struct xenisrc *isrc; | |||||||||
va_list ap; | va_list ap; | |||||||||
isrc = xen_intr_isrc(port_handle); | isrc = xen_intr_isrc_from_handle(port_handle); | |||||||||
Not Done Inline ActionsActually, I'm halfway tempted to rename "port_handle" to "handle" while I'm at it. Everywhere else it is "handle" for being passed in or "port_handlep" for a pointer being modified. Calling it "port_handle" here seems cause for confusion. ehem_freebsd_m5p.com: Actually, I'm halfway tempted to rename "port_handle" to "handle" while I'm at it. Everywhere… | ||||||||||
Not Done Inline ActionsUp to you, but I'm not very concerned here. The number of uses of port_handle[p] and handle are roughly equal in the current version of this file. mhorne: Up to you, but I'm not very concerned here. The number of uses of `port_handle[p]` and `handle`… | ||||||||||
if (isrc == NULL) | if (isrc == NULL) | |||||||||
return (EINVAL); | return (EINVAL); | |||||||||
va_start(ap, fmt); | va_start(ap, fmt); | |||||||||
vsnprintf(descr, sizeof(descr), fmt, ap); | vsnprintf(descr, sizeof(descr), fmt, ap); | |||||||||
va_end(ap); | va_end(ap); | |||||||||
return (intr_describe(isrc->xi_vector, isrc->xi_cookie, descr)); | return (intr_describe(isrc->xi_vector, isrc->xi_cookie, descr)); | |||||||||
} | } | |||||||||
void | void | |||||||||
xen_intr_unbind(xen_intr_handle_t *port_handlep) | xen_intr_unbind(xen_intr_handle_t *port_handlep) | |||||||||
{ | { | |||||||||
struct xenisrc *isrc; | struct xenisrc *isrc; | |||||||||
KASSERT(port_handlep != NULL, | KASSERT(port_handlep != NULL, | |||||||||
("NULL xen_intr_handle_t passed to xen_intr_unbind")); | ("NULL xen_intr_handle_t passed to xen_intr_unbind")); | |||||||||
isrc = xen_intr_isrc(*port_handlep); | isrc = xen_intr_isrc_from_handle(*port_handlep); | |||||||||
*port_handlep = NULL; | *port_handlep = NULL; | |||||||||
if (isrc == NULL) | if (isrc == NULL) | |||||||||
return; | return; | |||||||||
mtx_lock(&xen_intr_isrc_lock); | mtx_lock(&xen_intr_isrc_lock); | |||||||||
if (refcount_release(&isrc->xi_refcount) == 0) { | if (refcount_release(&isrc->xi_refcount) == 0) { | |||||||||
mtx_unlock(&xen_intr_isrc_lock); | mtx_unlock(&xen_intr_isrc_lock); | |||||||||
return; | return; | |||||||||
} | } | |||||||||
mtx_unlock(&xen_intr_isrc_lock); | mtx_unlock(&xen_intr_isrc_lock); | |||||||||
if (isrc->xi_cookie != NULL) | if (isrc->xi_cookie != NULL) | |||||||||
intr_remove_handler(isrc->xi_cookie); | intr_remove_handler(isrc->xi_cookie); | |||||||||
xen_intr_release_isrc(isrc); | xen_intr_release_isrc(isrc); | |||||||||
} | } | |||||||||
void | void | |||||||||
xen_intr_signal(xen_intr_handle_t handle) | xen_intr_signal(xen_intr_handle_t handle) | |||||||||
{ | { | |||||||||
struct xenisrc *isrc; | struct xenisrc *isrc; | |||||||||
isrc = xen_intr_isrc(handle); | isrc = xen_intr_isrc_from_handle(handle); | |||||||||
if (isrc != NULL) { | if (isrc != NULL) { | |||||||||
KASSERT(isrc->xi_type == EVTCHN_TYPE_PORT || | KASSERT(isrc->xi_type == EVTCHN_TYPE_PORT || | |||||||||
isrc->xi_type == EVTCHN_TYPE_IPI, | isrc->xi_type == EVTCHN_TYPE_IPI, | |||||||||
("evtchn_signal on something other than a local port")); | ("evtchn_signal on something other than a local port")); | |||||||||
struct evtchn_send send = { .port = isrc->xi_port }; | struct evtchn_send send = { .port = isrc->xi_port }; | |||||||||
(void)HYPERVISOR_event_channel_op(EVTCHNOP_send, &send); | (void)HYPERVISOR_event_channel_op(EVTCHNOP_send, &send); | |||||||||
} | } | |||||||||
} | } | |||||||||
evtchn_port_t | evtchn_port_t | |||||||||
xen_intr_port(xen_intr_handle_t handle) | xen_intr_port(xen_intr_handle_t handle) | |||||||||
{ | { | |||||||||
struct xenisrc *isrc; | struct xenisrc *isrc; | |||||||||
isrc = xen_intr_isrc(handle); | isrc = xen_intr_isrc_from_handle(handle); | |||||||||
if (isrc == NULL) | if (isrc == NULL) | |||||||||
return (0); | return (0); | |||||||||
return (isrc->xi_port); | return (isrc->xi_port); | |||||||||
} | } | |||||||||
int | int | |||||||||
xen_intr_add_handler(const char *name, driver_filter_t filter, | xen_intr_add_handler(const char *name, driver_filter_t filter, | |||||||||
driver_intr_t handler, void *arg, enum intr_type flags, | driver_intr_t handler, void *arg, enum intr_type flags, | |||||||||
xen_intr_handle_t handle) | xen_intr_handle_t handle) | |||||||||
{ | { | |||||||||
struct xenisrc *isrc; | struct xenisrc *isrc; | |||||||||
int error; | int error; | |||||||||
isrc = xen_intr_isrc(handle); | isrc = xen_intr_isrc_from_handle(handle); | |||||||||
if (isrc == NULL || isrc->xi_cookie != NULL) | if (isrc == NULL || isrc->xi_cookie != NULL) | |||||||||
return (EINVAL); | return (EINVAL); | |||||||||
error = intr_add_handler(name, isrc->xi_vector,filter, handler, arg, | error = intr_add_handler(name, isrc->xi_vector,filter, handler, arg, | |||||||||
flags|INTR_EXCL, &isrc->xi_cookie, 0); | flags|INTR_EXCL, &isrc->xi_cookie, 0); | |||||||||
if (error != 0) { | if (error != 0) { | |||||||||
printf( | printf( | |||||||||
"%s: xen_intr_add_handler: intr_add_handler failed: %d\n", | "%s: xen_intr_add_handler: intr_add_handler failed: %d\n", | |||||||||
Show All 17 Lines | xen_intr_get_evtchn_from_port(evtchn_port_t port, xen_intr_handle_t *handlep) | |||||||||
mtx_lock(&xen_intr_isrc_lock); | mtx_lock(&xen_intr_isrc_lock); | |||||||||
if (xen_intr_port_to_isrc[port] == NULL) { | if (xen_intr_port_to_isrc[port] == NULL) { | |||||||||
mtx_unlock(&xen_intr_isrc_lock); | mtx_unlock(&xen_intr_isrc_lock); | |||||||||
return (EINVAL); | return (EINVAL); | |||||||||
} | } | |||||||||
refcount_acquire(&xen_intr_port_to_isrc[port]->xi_refcount); | refcount_acquire(&xen_intr_port_to_isrc[port]->xi_refcount); | |||||||||
mtx_unlock(&xen_intr_isrc_lock); | mtx_unlock(&xen_intr_isrc_lock); | |||||||||
/* Assign the opaque handler (the event channel port) */ | /* Assign the opaque handler */ | |||||||||
*handlep = &xen_intr_port_to_isrc[port]->xi_vector; | *handlep = xen_intr_handle_from_isrc(xen_intr_port_to_isrc[port]); | |||||||||
return (0); | return (0); | |||||||||
} | } | |||||||||
#ifdef DDB | #ifdef DDB | |||||||||
static const char * | static const char * | |||||||||
xen_intr_print_type(enum evtchn_type type) | xen_intr_print_type(enum evtchn_type type) | |||||||||
{ | { | |||||||||
▲ Show 20 Lines • Show All 65 Lines • Show Last 20 Lines |
Since this is just a type cast, the helpers can be marked __inline or converted to macros.
Optionally you can shorten the name too, since they are private to this file, e.g. handle_from_xenisrc/xenisrc_from_handle.