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:
Roger Pau Monné 2015-02-16 16:30:42 +00:00
parent 537116c230
commit a2c5251281

View File

@ -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);