mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
[HVM] Route ISA IRQ 0 to IOAPIC GSI 2, just like 99% of native systems.
This is a built-in assumption of HPET 'legacy' IRQ routing, which is why we have changed to this routing strategy now. Signed-off-by: Keir Fraser <keir@xensource.com>
This commit is contained in:
1 parent
894243ac7b
commit
175eac1a6d
4 files changed
+29
-58
No files matched your search
@@ -69,16 +69,28 @@ int construct_madt(struct acpi_20_madt *madt)
|
||||
intsrcovr = (struct acpi_20_madt_intsrcovr *)(madt + 1);
|
||||
for ( i = 0; i < 16; i++ )
|
||||
{
|
||||
if ( !(PCI_ISA_IRQ_MASK & (1U << i)) )
|
||||
continue;
|
||||
|
||||
/* PCI: active-low level-triggered */
|
||||
memset(intsrcovr, 0, sizeof(*intsrcovr));
|
||||
intsrcovr->type = ACPI_INTERRUPT_SOURCE_OVERRIDE;
|
||||
intsrcovr->length = sizeof(*intsrcovr);
|
||||
intsrcovr->source = i;
|
||||
intsrcovr->gsi = i;
|
||||
intsrcovr->flags = 0xf;
|
||||
|
||||
if ( i == 0 )
|
||||
{
|
||||
/* ISA IRQ0 routed to IOAPIC GSI 2. */
|
||||
intsrcovr->gsi = 2;
|
||||
intsrcovr->flags = 0x0;
|
||||
}
|
||||
else if ( PCI_ISA_IRQ_MASK & (1U << i) )
|
||||
{
|
||||
/* PCI: active-low level-triggered. */
|
||||
intsrcovr->gsi = i;
|
||||
intsrcovr->flags = 0xf;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No need for a INT source override structure. */
|
||||
continue;
|
||||
}
|
||||
|
||||
offset += sizeof(*intsrcovr);
|
||||
intsrcovr++;
|
||||
|
||||
@@ -373,7 +373,7 @@ void create_mp_tables(void)
|
||||
{
|
||||
if ( i == 2 ) continue; /* skip the slave PIC connection */
|
||||
fill_mp_io_intr_entry((struct mp_io_intr_entry *)p,
|
||||
BUS_ID_ISA, i, IOAPIC_ID, i);
|
||||
BUS_ID_ISA, i, IOAPIC_ID, (i == 0) ? 2 : i);
|
||||
p += sizeof(struct mp_io_intr_entry);
|
||||
}
|
||||
|
||||
|
||||
+5
-48
@@ -97,9 +97,6 @@
|
||||
((timer_config(h, n) & HPET_TN_INT_ROUTE_CAP_MASK) \
|
||||
>> HPET_TN_INT_ROUTE_CAP_SHIFT)
|
||||
|
||||
#define timer_int_route_valid(h, n) \
|
||||
(timer_int_route_cap(h, n) & (1 << timer_int_route(h, n)))
|
||||
|
||||
#define hpet_time_after(a, b) ((int32_t)(b) -(int32_t)(a) < 0)
|
||||
#define hpet_time_after64(a, b) ((int64_t)(b) -(int64_t)(a) < 0)
|
||||
|
||||
@@ -409,54 +406,14 @@ struct hvm_mmio_handler hpet_mmio_handler = {
|
||||
.write_handler = hpet_write
|
||||
};
|
||||
|
||||
static void hpet_irq_assert(struct domain *d,
|
||||
unsigned int isa_irq, unsigned int intr)
|
||||
{
|
||||
struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
|
||||
|
||||
spin_lock(&hvm_irq->lock);
|
||||
|
||||
if ( !__test_and_set_bit(isa_irq, &hvm_irq->isa_irq) &&
|
||||
(hvm_irq->gsi_assert_count[isa_irq]++ == 0) )
|
||||
{
|
||||
vioapic_irq_positive_edge(d, intr);
|
||||
vpic_irq_positive_edge(d, isa_irq);
|
||||
}
|
||||
|
||||
spin_unlock(&hvm_irq->lock);
|
||||
}
|
||||
|
||||
static void hpet_irq_deassert(struct domain *d,
|
||||
unsigned int isa_irq, unsigned int intr)
|
||||
{
|
||||
hvm_isa_irq_deassert(d, isa_irq);
|
||||
}
|
||||
|
||||
static void hpet_set_irq(struct domain *d, int hpet_tn)
|
||||
{
|
||||
int irq, intr;
|
||||
|
||||
if ( (hpet_tn != 0) && (hpet_tn != 1) )
|
||||
return;
|
||||
|
||||
/* if LegacyReplacementRoute bit is set, HPET specification requires
|
||||
timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC,
|
||||
timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC.
|
||||
It's hard to distinguish NON-APIC and I/O APIC, so we set both PIC
|
||||
and I/O APIC here. Guest OS shall make proper mask setting to ensure
|
||||
only one interrupt is injected into it. */
|
||||
if ( hpet_tn == 0 )
|
||||
{
|
||||
irq = 0;
|
||||
intr = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
irq = intr = 8;
|
||||
}
|
||||
|
||||
hpet_irq_deassert(d, irq, intr);
|
||||
hpet_irq_assert(d, irq, intr);
|
||||
timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC. */
|
||||
int isa_irq = (hpet_tn == 0) ? 0 : 8;
|
||||
hvm_isa_irq_deassert(d, isa_irq);
|
||||
hvm_isa_irq_assert(d, isa_irq);
|
||||
}
|
||||
|
||||
static void hpet_route_interrupt(HPETState *h, unsigned int tn)
|
||||
@@ -465,7 +422,7 @@ static void hpet_route_interrupt(HPETState *h, unsigned int tn)
|
||||
struct domain *d = h->vcpu->domain;
|
||||
struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
|
||||
|
||||
if ( (tn_int_route >= VIOAPIC_NUM_PINS) || !timer_int_route_valid(h, tn) )
|
||||
if ( !(timer_int_route_cap(h, tn) & (1U << tn_int_route)) )
|
||||
{
|
||||
gdprintk(XENLOG_ERR,
|
||||
"HPET: timer%u: invalid interrupt route config\n", tn);
|
||||
|
||||
@@ -85,15 +85,16 @@ void hvm_isa_irq_assert(
|
||||
struct domain *d, unsigned int isa_irq)
|
||||
{
|
||||
struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
|
||||
unsigned int gsi = (isa_irq == 0) ? 2 : isa_irq;
|
||||
|
||||
ASSERT(isa_irq <= 15);
|
||||
|
||||
spin_lock(&hvm_irq->lock);
|
||||
|
||||
if ( !__test_and_set_bit(isa_irq, &hvm_irq->isa_irq) &&
|
||||
(hvm_irq->gsi_assert_count[isa_irq]++ == 0) )
|
||||
(hvm_irq->gsi_assert_count[gsi]++ == 0) )
|
||||
{
|
||||
vioapic_irq_positive_edge(d, isa_irq);
|
||||
vioapic_irq_positive_edge(d, gsi);
|
||||
vpic_irq_positive_edge(d, isa_irq);
|
||||
}
|
||||
|
||||
@@ -104,13 +105,14 @@ void hvm_isa_irq_deassert(
|
||||
struct domain *d, unsigned int isa_irq)
|
||||
{
|
||||
struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
|
||||
unsigned int gsi = (isa_irq == 0) ? 2 : isa_irq;
|
||||
|
||||
ASSERT(isa_irq <= 15);
|
||||
|
||||
spin_lock(&hvm_irq->lock);
|
||||
|
||||
if ( __test_and_clear_bit(isa_irq, &hvm_irq->isa_irq) &&
|
||||
(--hvm_irq->gsi_assert_count[isa_irq] == 0) )
|
||||
(--hvm_irq->gsi_assert_count[gsi] == 0) )
|
||||
vpic_irq_negative_edge(d, isa_irq);
|
||||
|
||||
spin_unlock(&hvm_irq->lock);
|
||||
|
||||