Changeset View
Changeset View
Standalone View
Standalone View
sys/x86/xen/xen_intr.c
Show First 20 Lines • Show All 107 Lines • ▼ Show 20 Lines | |||||
* location as the highest numbered event channel port. | * location as the highest numbered event channel port. | ||||
*/ | */ | ||||
DPCPU_DEFINE_STATIC(struct xen_intr_pcpu_data, xen_intr_pcpu) = { | DPCPU_DEFINE_STATIC(struct xen_intr_pcpu_data, xen_intr_pcpu) = { | ||||
.last_processed_l1i = LONG_BIT - 1, | .last_processed_l1i = LONG_BIT - 1, | ||||
.last_processed_l2i = LONG_BIT - 1 | .last_processed_l2i = LONG_BIT - 1 | ||||
}; | }; | ||||
DPCPU_DECLARE(struct vcpu_info *, vcpu_info); | DPCPU_DECLARE(struct vcpu_info *, vcpu_info); | ||||
#define XEN_EEXIST 17 /* Xen "already exists" error */ | |||||
#define XEN_ALLOCATE_VECTOR 0 /* Allocate a vector for this event channel */ | |||||
#define XEN_INVALID_EVTCHN 0 /* Invalid event channel */ | #define XEN_INVALID_EVTCHN 0 /* Invalid event channel */ | ||||
ehem_freebsd_m5p.com: I believe the one and //only// usage of `XEN_EEXIST` is the if statement on line 1185. As such… | |||||
#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. */ | 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_pirq; | |||||
int xi_virq; | 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_activehi:1; | u_int xi_activehi:1; | ||||
u_int xi_edgetrigger:1; | u_int xi_edgetrigger:1; | ||||
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); | ||||
static void xen_intr_enable_source(struct intsrc *isrc); | static void xen_intr_enable_source(struct intsrc *isrc); | ||||
static void xen_intr_disable_source(struct intsrc *isrc, int eoi); | static void xen_intr_disable_source(struct intsrc *isrc, int eoi); | ||||
static void xen_intr_eoi_source(struct intsrc *isrc); | static void xen_intr_eoi_source(struct intsrc *isrc); | ||||
static void xen_intr_enable_intr(struct intsrc *isrc); | static void xen_intr_enable_intr(struct intsrc *isrc); | ||||
static void xen_intr_disable_intr(struct intsrc *isrc); | static void xen_intr_disable_intr(struct intsrc *isrc); | ||||
static int xen_intr_vector(struct intsrc *isrc); | static int xen_intr_vector(struct intsrc *isrc); | ||||
static int xen_intr_source_pending(struct intsrc *isrc); | static int xen_intr_source_pending(struct intsrc *isrc); | ||||
static int xen_intr_config_intr(struct intsrc *isrc, | static int xen_intr_config_intr(struct intsrc *isrc, | ||||
enum intr_trigger trig, enum intr_polarity pol); | enum intr_trigger trig, enum intr_polarity pol); | ||||
static int xen_intr_assign_cpu(struct intsrc *isrc, u_int apic_id); | static int xen_intr_assign_cpu(struct intsrc *isrc, u_int apic_id); | ||||
static void xen_intr_pirq_enable_source(struct intsrc *isrc); | |||||
static void xen_intr_pirq_disable_source(struct intsrc *isrc, int eoi); | |||||
static void xen_intr_pirq_eoi_source(struct intsrc *isrc); | |||||
static void xen_intr_pirq_enable_intr(struct intsrc *isrc); | |||||
static void xen_intr_pirq_disable_intr(struct intsrc *isrc); | |||||
static int xen_intr_pirq_config_intr(struct intsrc *isrc, | |||||
enum intr_trigger trig, enum intr_polarity pol); | |||||
/** | /** | ||||
* PIC interface for all event channel port types except physical IRQs. | * PIC interface for all event channel port types except physical IRQs. | ||||
*/ | */ | ||||
struct pic xen_intr_pic = { | struct pic xen_intr_pic = { | ||||
.pic_enable_source = xen_intr_enable_source, | .pic_enable_source = xen_intr_enable_source, | ||||
.pic_disable_source = xen_intr_disable_source, | .pic_disable_source = xen_intr_disable_source, | ||||
.pic_eoi_source = xen_intr_eoi_source, | .pic_eoi_source = xen_intr_eoi_source, | ||||
.pic_enable_intr = xen_intr_enable_intr, | .pic_enable_intr = xen_intr_enable_intr, | ||||
.pic_disable_intr = xen_intr_disable_intr, | .pic_disable_intr = xen_intr_disable_intr, | ||||
.pic_vector = xen_intr_vector, | .pic_vector = xen_intr_vector, | ||||
.pic_source_pending = xen_intr_source_pending, | .pic_source_pending = xen_intr_source_pending, | ||||
.pic_suspend = xen_intr_suspend, | .pic_suspend = xen_intr_suspend, | ||||
.pic_resume = xen_intr_resume, | .pic_resume = xen_intr_resume, | ||||
.pic_config_intr = xen_intr_config_intr, | .pic_config_intr = xen_intr_config_intr, | ||||
.pic_assign_cpu = xen_intr_assign_cpu | .pic_assign_cpu = xen_intr_assign_cpu | ||||
}; | }; | ||||
/** | |||||
* PIC interface for all event channel representing | |||||
* physical interrupt sources. | |||||
*/ | |||||
struct pic xen_intr_pirq_pic = { | |||||
#ifdef __amd64__ | |||||
.pic_register_sources = xenpv_register_pirqs, | |||||
#endif | |||||
.pic_enable_source = xen_intr_pirq_enable_source, | |||||
.pic_disable_source = xen_intr_pirq_disable_source, | |||||
.pic_eoi_source = xen_intr_pirq_eoi_source, | |||||
.pic_enable_intr = xen_intr_pirq_enable_intr, | |||||
.pic_disable_intr = xen_intr_pirq_disable_intr, | |||||
.pic_vector = xen_intr_vector, | |||||
.pic_source_pending = xen_intr_source_pending, | |||||
.pic_config_intr = xen_intr_pirq_config_intr, | |||||
.pic_assign_cpu = xen_intr_assign_cpu | |||||
}; | |||||
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 boolean_t xen_intr_pirq_eoi_map_enabled; | |||||
/*------------------------- Private Functions --------------------------------*/ | /*------------------------- Private Functions --------------------------------*/ | ||||
/** | /** | ||||
* 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. | ||||
* | * | ||||
▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | |||||
* 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, int vector) | xen_intr_alloc_isrc(enum evtchn_type type) | ||||
Not Done Inline Actionsvector is now being unconditionally set below and the passed-in value ignored. As such vector should be a local variable instead of being an argument. ehem_freebsd_m5p.com: `vector` is now being //unconditionally// set below and the passed-in value **ignored**. As… | |||||
{ | { | ||||
static int warned; | static int warned; | ||||
struct xenisrc *isrc; | struct xenisrc *isrc; | ||||
unsigned int vector; | |||||
KASSERT(mtx_owned(&xen_intr_isrc_lock), ("Evtchn alloc lock not held")); | KASSERT(mtx_owned(&xen_intr_isrc_lock), ("Evtchn alloc lock not held")); | ||||
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("xen_intr_alloc: Event channels exhausted.\n"); | printf("xen_intr_alloc: Event channels exhausted.\n"); | ||||
} | } | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
if (type != EVTCHN_TYPE_PIRQ) { | |||||
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_intsrc.is_pic = | isrc->xi_intsrc.is_pic = &xen_intr_pic; | ||||
(type == EVTCHN_TYPE_PIRQ) ? &xen_intr_pirq_pic : &xen_intr_pic; | |||||
isrc->xi_vector = vector; | isrc->xi_vector = vector; | ||||
isrc->xi_type = type; | isrc->xi_type = type; | ||||
intr_register_source(&isrc->xi_intsrc); | intr_register_source(&isrc->xi_intsrc); | ||||
mtx_lock(&xen_intr_isrc_lock); | mtx_lock(&xen_intr_isrc_lock); | ||||
return (isrc); | return (isrc); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | if (port_handlep == NULL) { | ||||
printf("%s: xen_intr_bind_isrc: Bad event handle\n", | printf("%s: xen_intr_bind_isrc: Bad event handle\n", | ||||
intr_owner); | intr_owner); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
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(type); | ||||
if (isrc == NULL) { | if (isrc == NULL) { | ||||
isrc = xen_intr_alloc_isrc(type, XEN_ALLOCATE_VECTOR); | isrc = xen_intr_alloc_isrc(type); | ||||
Not Done Inline ActionsThis is the only call to xen_intr_alloc_isrc() which remains. The second argument should be removed (since it is now ignored). Since this was the only use of XEN_ALLOCATE_VECTOR, that in turn allows removal of XEN_ALLOCATE_VECTOR. ehem_freebsd_m5p.com: This is the only call to xen_intr_alloc_isrc() which remains. The second argument //should//… | |||||
if (isrc == NULL) { | if (isrc == NULL) { | ||||
mtx_unlock(&xen_intr_isrc_lock); | mtx_unlock(&xen_intr_isrc_lock); | ||||
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); | ||||
▲ Show 20 Lines • Show All 199 Lines • ▼ Show 20 Lines | #endif | ||||
critical_exit(); | critical_exit(); | ||||
} | } | ||||
static int | static int | ||||
xen_intr_init(void *dummy __unused) | xen_intr_init(void *dummy __unused) | ||||
{ | { | ||||
shared_info_t *s = HYPERVISOR_shared_info; | shared_info_t *s = HYPERVISOR_shared_info; | ||||
struct xen_intr_pcpu_data *pcpu; | struct xen_intr_pcpu_data *pcpu; | ||||
struct physdev_pirq_eoi_gmfn eoi_gmfn; | int i; | ||||
int i, rc; | |||||
if (!xen_domain()) | if (!xen_domain()) | ||||
return (0); | return (0); | ||||
mtx_init(&xen_intr_isrc_lock, "xen-irq-lock", NULL, MTX_DEF); | mtx_init(&xen_intr_isrc_lock, "xen-irq-lock", NULL, MTX_DEF); | ||||
/* | /* | ||||
* Set the per-cpu mask of CPU#0 to enable all, since by default all | * Set the per-cpu mask of CPU#0 to enable all, since by default all | ||||
* event channels are bound to CPU#0. | * event channels are bound to CPU#0. | ||||
*/ | */ | ||||
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], ~0); | ||||
/* Try to register PIRQ EOI map */ | |||||
xen_intr_pirq_eoi_map = malloc(PAGE_SIZE, M_XENINTR, M_WAITOK | M_ZERO); | |||||
eoi_gmfn.gmfn = atop(vtophys(xen_intr_pirq_eoi_map)); | |||||
rc = HYPERVISOR_physdev_op(PHYSDEVOP_pirq_eoi_gmfn_v2, &eoi_gmfn); | |||||
if (rc != 0 && bootverbose) | |||||
printf("Xen interrupts: unable to register PIRQ EOI map\n"); | |||||
else | |||||
xen_intr_pirq_eoi_map_enabled = true; | |||||
intr_register_pic(&xen_intr_pic); | intr_register_pic(&xen_intr_pic); | ||||
if (xen_pv_domain() && xen_initial_domain()) | |||||
intr_register_pic(&xen_intr_pirq_pic); | |||||
if (bootverbose) | if (bootverbose) | ||||
printf("Xen interrupt system initialized\n"); | printf("Xen interrupt system initialized\n"); | ||||
return (0); | return (0); | ||||
} | } | ||||
SYSINIT(xen_intr_init, SI_SUB_INTR, SI_ORDER_SECOND, xen_intr_init, NULL); | SYSINIT(xen_intr_init, SI_SUB_INTR, SI_ORDER_SECOND, xen_intr_init, NULL); | ||||
▲ Show 20 Lines • Show All 339 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
xen_intr_enable_intr(struct intsrc *base_isrc) | xen_intr_enable_intr(struct intsrc *base_isrc) | ||||
{ | { | ||||
struct xenisrc *isrc = (struct xenisrc *)base_isrc; | struct xenisrc *isrc = (struct xenisrc *)base_isrc; | ||||
evtchn_unmask_port(isrc->xi_port); | evtchn_unmask_port(isrc->xi_port); | ||||
} | } | ||||
/*------------------ Physical Interrupt Source PIC Functions -----------------*/ | |||||
/* | |||||
* Mask a level triggered interrupt source. | |||||
* | |||||
* \param isrc The interrupt source to mask (if necessary). | |||||
* \param eoi If non-zero, perform any necessary end-of-interrupt | |||||
* acknowledgements. | |||||
*/ | |||||
static void | |||||
xen_intr_pirq_disable_source(struct intsrc *base_isrc, int eoi) | |||||
{ | |||||
struct xenisrc *isrc; | |||||
isrc = (struct xenisrc *)base_isrc; | |||||
if (isrc->xi_edgetrigger == 0) | |||||
evtchn_mask_port(isrc->xi_port); | |||||
if (eoi == PIC_EOI) | |||||
xen_intr_pirq_eoi_source(base_isrc); | |||||
} | |||||
/* | |||||
* Unmask a level triggered interrupt source. | |||||
* | |||||
* \param isrc The interrupt source to unmask (if necessary). | |||||
*/ | |||||
static void | |||||
xen_intr_pirq_enable_source(struct intsrc *base_isrc) | |||||
{ | |||||
struct xenisrc *isrc; | |||||
isrc = (struct xenisrc *)base_isrc; | |||||
if (isrc->xi_edgetrigger == 0) | |||||
evtchn_unmask_port(isrc->xi_port); | |||||
} | |||||
/* | |||||
* Perform any necessary end-of-interrupt acknowledgements. | |||||
* | |||||
* \param isrc The interrupt source to EOI. | |||||
*/ | |||||
static void | |||||
xen_intr_pirq_eoi_source(struct intsrc *base_isrc) | |||||
{ | |||||
struct xenisrc *isrc; | |||||
int error; | |||||
isrc = (struct xenisrc *)base_isrc; | |||||
if (xen_test_bit(isrc->xi_pirq, xen_intr_pirq_eoi_map)) { | |||||
struct physdev_eoi eoi = { .irq = isrc->xi_pirq }; | |||||
error = HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi); | |||||
if (error != 0) | |||||
panic("Unable to EOI PIRQ#%d: %d\n", | |||||
isrc->xi_pirq, error); | |||||
} | |||||
} | |||||
/* | |||||
* Enable and unmask the interrupt source. | |||||
* | |||||
* \param isrc The interrupt source to enable. | |||||
*/ | |||||
static void | |||||
xen_intr_pirq_enable_intr(struct intsrc *base_isrc) | |||||
{ | |||||
struct xenisrc *isrc; | |||||
struct evtchn_bind_pirq bind_pirq; | |||||
struct physdev_irq_status_query irq_status; | |||||
int error; | |||||
isrc = (struct xenisrc *)base_isrc; | |||||
if (!xen_intr_pirq_eoi_map_enabled) { | |||||
irq_status.irq = isrc->xi_pirq; | |||||
error = HYPERVISOR_physdev_op(PHYSDEVOP_irq_status_query, | |||||
&irq_status); | |||||
if (error) | |||||
panic("unable to get status of IRQ#%d", isrc->xi_pirq); | |||||
if (irq_status.flags & XENIRQSTAT_needs_eoi) { | |||||
/* | |||||
* Since the dynamic PIRQ EOI map is not available | |||||
* mark the PIRQ as needing EOI unconditionally. | |||||
*/ | |||||
xen_set_bit(isrc->xi_pirq, xen_intr_pirq_eoi_map); | |||||
} | |||||
} | |||||
bind_pirq.pirq = isrc->xi_pirq; | |||||
bind_pirq.flags = isrc->xi_edgetrigger ? 0 : BIND_PIRQ__WILL_SHARE; | |||||
error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_pirq, &bind_pirq); | |||||
if (error) | |||||
panic("unable to bind IRQ#%d", isrc->xi_pirq); | |||||
isrc->xi_port = bind_pirq.port; | |||||
mtx_lock(&xen_intr_isrc_lock); | |||||
KASSERT((xen_intr_port_to_isrc[bind_pirq.port] == NULL), | |||||
("trying to override an already setup event channel port")); | |||||
xen_intr_port_to_isrc[bind_pirq.port] = isrc; | |||||
mtx_unlock(&xen_intr_isrc_lock); | |||||
evtchn_unmask_port(isrc->xi_port); | |||||
} | |||||
/* | |||||
* Disable an interrupt source. | |||||
* | |||||
* \param isrc The interrupt source to disable. | |||||
*/ | |||||
static void | |||||
xen_intr_pirq_disable_intr(struct intsrc *base_isrc) | |||||
{ | |||||
struct xenisrc *isrc; | |||||
struct evtchn_close close; | |||||
int error; | |||||
isrc = (struct xenisrc *)base_isrc; | |||||
evtchn_mask_port(isrc->xi_port); | |||||
close.port = isrc->xi_port; | |||||
error = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close); | |||||
if (error) | |||||
panic("unable to close event channel %d IRQ#%d", | |||||
isrc->xi_port, isrc->xi_pirq); | |||||
mtx_lock(&xen_intr_isrc_lock); | |||||
xen_intr_port_to_isrc[isrc->xi_port] = NULL; | |||||
mtx_unlock(&xen_intr_isrc_lock); | |||||
isrc->xi_port = 0; | |||||
} | |||||
/** | |||||
* Perform configuration of an interrupt source. | |||||
* | |||||
* \param isrc The interrupt source to configure. | |||||
* \param trig Edge or level. | |||||
* \param pol Active high or low. | |||||
* | |||||
* \returns 0 if no events are pending, otherwise non-zero. | |||||
*/ | |||||
static int | |||||
xen_intr_pirq_config_intr(struct intsrc *base_isrc, enum intr_trigger trig, | |||||
enum intr_polarity pol) | |||||
{ | |||||
struct xenisrc *isrc = (struct xenisrc *)base_isrc; | |||||
struct physdev_setup_gsi setup_gsi; | |||||
int error; | |||||
KASSERT(!(trig == INTR_TRIGGER_CONFORM || pol == INTR_POLARITY_CONFORM), | |||||
("%s: Conforming trigger or polarity\n", __func__)); | |||||
setup_gsi.gsi = isrc->xi_pirq; | |||||
setup_gsi.triggering = trig == INTR_TRIGGER_EDGE ? 0 : 1; | |||||
setup_gsi.polarity = pol == INTR_POLARITY_HIGH ? 0 : 1; | |||||
error = HYPERVISOR_physdev_op(PHYSDEVOP_setup_gsi, &setup_gsi); | |||||
if (error == -XEN_EEXIST) { | |||||
if ((isrc->xi_edgetrigger && (trig != INTR_TRIGGER_EDGE)) || | |||||
(isrc->xi_activehi && (pol != INTR_POLARITY_HIGH))) | |||||
panic("unable to reconfigure interrupt IRQ#%d", | |||||
isrc->xi_pirq); | |||||
error = 0; | |||||
} | |||||
if (error) | |||||
panic("unable to configure IRQ#%d\n", isrc->xi_pirq); | |||||
isrc->xi_activehi = pol == INTR_POLARITY_HIGH ? 1 : 0; | |||||
isrc->xi_edgetrigger = trig == INTR_TRIGGER_EDGE ? 1 : 0; | |||||
return (0); | |||||
} | |||||
/*--------------------------- 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; | ||||
▲ Show 20 Lines • Show All 199 Lines • ▼ Show 20 Lines | #ifdef SMP | ||||
isrc->xi_close = 1; | isrc->xi_close = 1; | ||||
return (0); | return (0); | ||||
#else | #else | ||||
return (EOPNOTSUPP); | return (EOPNOTSUPP); | ||||
#endif | #endif | ||||
} | } | ||||
int | int | ||||
xen_register_pirq(int vector, enum intr_trigger trig, enum intr_polarity pol) | |||||
{ | |||||
struct physdev_map_pirq map_pirq; | |||||
struct xenisrc *isrc; | |||||
int error; | |||||
if (vector == 0) | |||||
return (EINVAL); | |||||
if (bootverbose) | |||||
printf("xen: register IRQ#%d\n", vector); | |||||
map_pirq.domid = DOMID_SELF; | |||||
map_pirq.type = MAP_PIRQ_TYPE_GSI; | |||||
map_pirq.index = vector; | |||||
map_pirq.pirq = vector; | |||||
error = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_pirq); | |||||
if (error) { | |||||
printf("xen: unable to map IRQ#%d\n", vector); | |||||
return (error); | |||||
} | |||||
mtx_lock(&xen_intr_isrc_lock); | |||||
isrc = xen_intr_alloc_isrc(EVTCHN_TYPE_PIRQ, vector); | |||||
mtx_unlock(&xen_intr_isrc_lock); | |||||
KASSERT((isrc != NULL), ("xen: unable to allocate isrc for interrupt")); | |||||
isrc->xi_pirq = vector; | |||||
isrc->xi_activehi = pol == INTR_POLARITY_HIGH ? 1 : 0; | |||||
isrc->xi_edgetrigger = trig == INTR_TRIGGER_EDGE ? 1 : 0; | |||||
return (0); | |||||
} | |||||
int | |||||
xen_register_msi(device_t dev, int vector, int count) | |||||
{ | |||||
struct physdev_map_pirq msi_irq; | |||||
struct xenisrc *isrc; | |||||
int ret; | |||||
memset(&msi_irq, 0, sizeof(msi_irq)); | |||||
msi_irq.domid = DOMID_SELF; | |||||
msi_irq.type = count == 1 ? | |||||
MAP_PIRQ_TYPE_MSI_SEG : MAP_PIRQ_TYPE_MULTI_MSI; | |||||
msi_irq.index = -1; | |||||
msi_irq.pirq = -1; | |||||
msi_irq.bus = pci_get_bus(dev) | (pci_get_domain(dev) << 16); | |||||
msi_irq.devfn = (pci_get_slot(dev) << 3) | pci_get_function(dev); | |||||
msi_irq.entry_nr = count; | |||||
ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &msi_irq); | |||||
if (ret != 0) | |||||
return (ret); | |||||
if (count != msi_irq.entry_nr) { | |||||
panic("unable to setup all requested MSI vectors " | |||||
"(expected %d got %d)", count, msi_irq.entry_nr); | |||||
} | |||||
mtx_lock(&xen_intr_isrc_lock); | |||||
for (int i = 0; i < count; i++) { | |||||
isrc = xen_intr_alloc_isrc(EVTCHN_TYPE_PIRQ, vector + i); | |||||
KASSERT(isrc != NULL, | |||||
("xen: unable to allocate isrc for interrupt")); | |||||
isrc->xi_pirq = msi_irq.pirq + i; | |||||
/* MSI interrupts are always edge triggered */ | |||||
isrc->xi_edgetrigger = 1; | |||||
} | |||||
mtx_unlock(&xen_intr_isrc_lock); | |||||
return (0); | |||||
} | |||||
int | |||||
xen_release_msi(int vector) | |||||
{ | |||||
struct physdev_unmap_pirq unmap; | |||||
struct xenisrc *isrc; | |||||
int ret; | |||||
isrc = (struct xenisrc *)intr_lookup_source(vector); | |||||
if (isrc == NULL) | |||||
return (ENXIO); | |||||
unmap.pirq = isrc->xi_pirq; | |||||
ret = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap); | |||||
if (ret != 0) | |||||
return (ret); | |||||
xen_intr_release_isrc(isrc); | |||||
return (0); | |||||
} | |||||
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(port_handle); | ||||
if (isrc == NULL) | if (isrc == NULL) | ||||
▲ Show 20 Lines • Show All 106 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
#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) | ||||
{ | { | ||||
static const char *evtchn_type_to_string[EVTCHN_TYPE_COUNT] = { | static const char *evtchn_type_to_string[EVTCHN_TYPE_COUNT] = { | ||||
[EVTCHN_TYPE_UNBOUND] = "UNBOUND", | [EVTCHN_TYPE_UNBOUND] = "UNBOUND", | ||||
[EVTCHN_TYPE_PIRQ] = "PIRQ", | |||||
[EVTCHN_TYPE_VIRQ] = "VIRQ", | [EVTCHN_TYPE_VIRQ] = "VIRQ", | ||||
[EVTCHN_TYPE_IPI] = "IPI", | [EVTCHN_TYPE_IPI] = "IPI", | ||||
[EVTCHN_TYPE_PORT] = "PORT", | [EVTCHN_TYPE_PORT] = "PORT", | ||||
}; | }; | ||||
if (type >= EVTCHN_TYPE_COUNT) | if (type >= EVTCHN_TYPE_COUNT) | ||||
return ("UNKNOWN"); | return ("UNKNOWN"); | ||||
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; | 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_PIRQ) { | |||||
db_printf("\tPirq: %d ActiveHi: %d EdgeTrigger: %d " | |||||
"NeedsEOI: %d\n", | |||||
isrc->xi_pirq, isrc->xi_activehi, isrc->xi_edgetrigger, | |||||
!!xen_test_bit(isrc->xi_pirq, xen_intr_pirq_eoi_map)); | |||||
} | |||||
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: "); | ||||
Show All 28 Lines |
I believe the one and only usage of XEN_EEXIST is the if statement on line 1185. As such I would suggest removing this #define of XEN_EEXIST due to the removal of line 1185.