xen/intr: improve PIRQ handling
Improve and cleanup the Xen PIRQ event channel code: - Remove the xi_shared field as it is unused. - Clean the "pending" bit in the EOI handler, this is more similar to how native interrupts are handled. - Don't mask edge triggered PIRQs, edge trigger interrupts cannot be masked. - Panic if PHYSDEVOP_eoi fails. - Remove the usage of the PHYSDEVOP_alloc_irq_vector hypercall because it's just a no-op in the Xen versions that are supported by FreeBSD Dom0. Sponsored by: Citrix Systems R&D
This commit is contained in:
parent
537116c230
commit
a2c5251281
@ -126,7 +126,6 @@ struct xenisrc {
|
||||
int xi_virq;
|
||||
void *xi_cookie;
|
||||
u_int xi_close:1; /* close on unbind? */
|
||||
u_int xi_shared:1; /* Shared with other domains. */
|
||||
u_int xi_activehi:1;
|
||||
u_int xi_edgetrigger:1;
|
||||
};
|
||||
@ -579,11 +578,12 @@ xen_intr_handle_upcall(struct trapframe *trap_frame)
|
||||
|
||||
/* process port */
|
||||
port = (l1i * LONG_BIT) + l2i;
|
||||
synch_clear_bit(port, &s->evtchn_pending[0]);
|
||||
|
||||
isrc = xen_intr_port_to_isrc[port];
|
||||
if (__predict_false(isrc == NULL))
|
||||
if (__predict_false(isrc == NULL)) {
|
||||
synch_clear_bit(port, &s->evtchn_pending[0]);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Make sure we are firing on the right vCPU */
|
||||
KASSERT((isrc->xi_cpu == PCPU_GET(cpuid)),
|
||||
@ -932,6 +932,9 @@ xen_intr_assign_cpu(struct intsrc *base_isrc, u_int apic_id)
|
||||
static void
|
||||
xen_intr_disable_source(struct intsrc *isrc, int eoi)
|
||||
{
|
||||
|
||||
if (eoi == PIC_EOI)
|
||||
xen_intr_eoi_source(isrc);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -950,8 +953,13 @@ xen_intr_enable_source(struct intsrc *isrc)
|
||||
* \param isrc The interrupt source to EOI.
|
||||
*/
|
||||
static void
|
||||
xen_intr_eoi_source(struct intsrc *isrc)
|
||||
xen_intr_eoi_source(struct intsrc *base_isrc)
|
||||
{
|
||||
struct xenisrc *isrc;
|
||||
|
||||
isrc = (struct xenisrc *)base_isrc;
|
||||
synch_clear_bit(isrc->xi_port,
|
||||
&HYPERVISOR_shared_info->evtchn_pending[0]);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -981,8 +989,9 @@ xen_intr_pirq_disable_source(struct intsrc *base_isrc, int eoi)
|
||||
struct xenisrc *isrc;
|
||||
|
||||
isrc = (struct xenisrc *)base_isrc;
|
||||
evtchn_mask_port(isrc->xi_port);
|
||||
|
||||
if (isrc->xi_edgetrigger == 0)
|
||||
evtchn_mask_port(isrc->xi_port);
|
||||
if (eoi == PIC_EOI)
|
||||
xen_intr_pirq_eoi_source(base_isrc);
|
||||
}
|
||||
@ -998,6 +1007,8 @@ 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);
|
||||
}
|
||||
|
||||
@ -1010,13 +1021,19 @@ static void
|
||||
xen_intr_pirq_eoi_source(struct intsrc *base_isrc)
|
||||
{
|
||||
struct xenisrc *isrc;
|
||||
int error;
|
||||
|
||||
/* XXX Use shared page of flags for this. */
|
||||
isrc = (struct xenisrc *)base_isrc;
|
||||
|
||||
synch_clear_bit(isrc->xi_port,
|
||||
&HYPERVISOR_shared_info->evtchn_pending[0]);
|
||||
if (test_bit(isrc->xi_pirq, xen_intr_pirq_eoi_map)) {
|
||||
struct physdev_eoi eoi = { .irq = isrc->xi_pirq };
|
||||
|
||||
(void)HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi);
|
||||
error = HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi);
|
||||
if (error != 0)
|
||||
panic("Unable to EOI PIRQ#%d: %d\n",
|
||||
isrc->xi_pirq, error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1361,7 +1378,6 @@ int
|
||||
xen_register_pirq(int vector, enum intr_trigger trig, enum intr_polarity pol)
|
||||
{
|
||||
struct physdev_map_pirq map_pirq;
|
||||
struct physdev_irq alloc_pirq;
|
||||
struct xenisrc *isrc;
|
||||
int error;
|
||||
|
||||
@ -1382,14 +1398,6 @@ xen_register_pirq(int vector, enum intr_trigger trig, enum intr_polarity pol)
|
||||
return (error);
|
||||
}
|
||||
|
||||
alloc_pirq.irq = vector;
|
||||
alloc_pirq.vector = 0;
|
||||
error = HYPERVISOR_physdev_op(PHYSDEVOP_alloc_irq_vector, &alloc_pirq);
|
||||
if (error) {
|
||||
printf("xen: unable to alloc PIRQ for 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);
|
||||
@ -1432,6 +1440,8 @@ xen_register_msi(device_t dev, int vector, int count)
|
||||
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);
|
||||
|
||||
@ -1573,10 +1583,9 @@ xen_intr_dump_port(struct xenisrc *isrc)
|
||||
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 Shared: %d\n",
|
||||
"NeedsEOI: %d\n",
|
||||
isrc->xi_pirq, isrc->xi_activehi, isrc->xi_edgetrigger,
|
||||
!!test_bit(isrc->xi_pirq, xen_intr_pirq_eoi_map),
|
||||
isrc->xi_shared);
|
||||
!!test_bit(isrc->xi_pirq, xen_intr_pirq_eoi_map));
|
||||
}
|
||||
if (isrc->xi_type == EVTCHN_TYPE_VIRQ)
|
||||
db_printf("\tVirq: %d\n", isrc->xi_virq);
|
||||
|
Loading…
Reference in New Issue
Block a user