160 lines
4.9 KiB
Diff
160 lines
4.9 KiB
Diff
|
References: bnc#713503
|
||
|
|
||
|
# HG changeset patch
|
||
|
# User Jan Beulich <jbeulich@suse.com>
|
||
|
# Date 1321604484 -3600
|
||
|
# Node ID f29b5bd6e25fd78409baa5461914c67065f7579f
|
||
|
# Parent 0d50e704834fb53c6c86b8b0badd19d88e73c4ed
|
||
|
x86/IRQ: prevent vector sharing within IO-APICs
|
||
|
|
||
|
Following the prevention of vector sharing for MSIs, this change
|
||
|
enforces the same within IO-APICs: Pin based interrupts use the IO-APIC
|
||
|
as their identifying device under the AMD IOMMU (and just like for
|
||
|
MSIs, only the identifying device is used to remap interrupts here,
|
||
|
with no regard to an interrupt's destination).
|
||
|
|
||
|
Additionally, LAPIC initiated EOIs (for level triggered interrupts) too
|
||
|
use only the vector for identifying which interrupts to end. While this
|
||
|
generally causes no significant problem (at worst an interrupt would be
|
||
|
re-raised without a new interrupt event actually having occurred), it
|
||
|
still seems better to avoid the situation.
|
||
|
|
||
|
For this second aspect, a distinction is being made between the
|
||
|
traditional and the directed-EOI cases: In the former, vectors should
|
||
|
not be shared throughout all IO-APICs in the system, while in the
|
||
|
latter case only individual IO-APICs need to be contrained (or, if the
|
||
|
firmware indicates so, sub- groups of them having the same GSI appear
|
||
|
at multiple pins).
|
||
|
|
||
|
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||
|
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||
|
|
||
|
--- a/xen/arch/x86/io_apic.c
|
||
|
+++ b/xen/arch/x86/io_apic.c
|
||
|
@@ -69,6 +69,34 @@ int __read_mostly nr_ioapics;
|
||
|
|
||
|
#define ioapic_has_eoi_reg(apic) (mp_ioapics[(apic)].mpc_apicver >= 0x20)
|
||
|
|
||
|
+static int apic_pin_2_gsi_irq(int apic, int pin);
|
||
|
+
|
||
|
+static vmask_t *__read_mostly vector_map[MAX_IO_APICS];
|
||
|
+
|
||
|
+static void share_vector_maps(unsigned int src, unsigned int dst)
|
||
|
+{
|
||
|
+ unsigned int pin;
|
||
|
+
|
||
|
+ if (vector_map[src] == vector_map[dst])
|
||
|
+ return;
|
||
|
+
|
||
|
+ bitmap_or(vector_map[src]->_bits, vector_map[src]->_bits,
|
||
|
+ vector_map[dst]->_bits, NR_VECTORS);
|
||
|
+
|
||
|
+ for (pin = 0; pin < nr_ioapic_registers[dst]; ++pin) {
|
||
|
+ int irq = apic_pin_2_gsi_irq(dst, pin);
|
||
|
+ struct irq_cfg *cfg;
|
||
|
+
|
||
|
+ if (irq < 0)
|
||
|
+ continue;
|
||
|
+ cfg = irq_cfg(irq);
|
||
|
+ if (cfg->used_vectors == vector_map[dst])
|
||
|
+ cfg->used_vectors = vector_map[src];
|
||
|
+ }
|
||
|
+
|
||
|
+ vector_map[dst] = vector_map[src];
|
||
|
+}
|
||
|
+
|
||
|
/*
|
||
|
* This is performance-critical, we want to do it O(1)
|
||
|
*
|
||
|
@@ -109,6 +137,7 @@ static void add_pin_to_irq(unsigned int
|
||
|
}
|
||
|
entry->apic = apic;
|
||
|
entry->pin = pin;
|
||
|
+ share_vector_maps(irq_2_pin[irq].apic, apic);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
@@ -124,6 +153,7 @@ static void __init replace_pin_at_irq(un
|
||
|
if (entry->apic == oldapic && entry->pin == oldpin) {
|
||
|
entry->apic = newapic;
|
||
|
entry->pin = newpin;
|
||
|
+ share_vector_maps(oldapic, newapic);
|
||
|
}
|
||
|
if (!entry->next)
|
||
|
break;
|
||
|
@@ -131,6 +161,16 @@ static void __init replace_pin_at_irq(un
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+vmask_t *io_apic_get_used_vector_map(unsigned int irq)
|
||
|
+{
|
||
|
+ struct irq_pin_list *entry = irq_2_pin + irq;
|
||
|
+
|
||
|
+ if (entry->pin == -1)
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ return vector_map[entry->apic];
|
||
|
+}
|
||
|
+
|
||
|
struct IO_APIC_route_entry **alloc_ioapic_entries(void)
|
||
|
{
|
||
|
int apic;
|
||
|
@@ -1314,6 +1354,18 @@ static void __init enable_IO_APIC(void)
|
||
|
for (i = irq_2_pin_free_entry = nr_irqs_gsi; i < PIN_MAP_SIZE; i++)
|
||
|
irq_2_pin[i].next = i + 1;
|
||
|
|
||
|
+ if (directed_eoi_enabled) {
|
||
|
+ for (apic = 0; apic < nr_ioapics; apic++) {
|
||
|
+ vector_map[apic] = xzalloc(vmask_t);
|
||
|
+ BUG_ON(!vector_map[apic]);
|
||
|
+ }
|
||
|
+ } else {
|
||
|
+ vector_map[0] = xzalloc(vmask_t);
|
||
|
+ BUG_ON(!vector_map[0]);
|
||
|
+ for (apic = 1; apic < nr_ioapics; apic++)
|
||
|
+ vector_map[apic] = vector_map[0];
|
||
|
+ }
|
||
|
+
|
||
|
for(apic = 0; apic < nr_ioapics; apic++) {
|
||
|
int pin;
|
||
|
/* See if any of the pins is in ExtINT mode */
|
||
|
@@ -2479,13 +2531,12 @@ int ioapic_guest_write(unsigned long phy
|
||
|
}
|
||
|
|
||
|
if ( cfg->vector <= 0 || cfg->vector > LAST_DYNAMIC_VECTOR ) {
|
||
|
+ add_pin_to_irq(irq, apic, pin);
|
||
|
vector = assign_irq_vector(irq);
|
||
|
if ( vector < 0 )
|
||
|
return vector;
|
||
|
|
||
|
printk(XENLOG_INFO "allocated vector %02x for irq %d\n", vector, irq);
|
||
|
-
|
||
|
- add_pin_to_irq(irq, apic, pin);
|
||
|
}
|
||
|
spin_lock(&pcidevs_lock);
|
||
|
spin_lock(&dom0->event_lock);
|
||
|
--- a/xen/arch/x86/irq.c
|
||
|
+++ b/xen/arch/x86/irq.c
|
||
|
@@ -403,6 +403,11 @@ static vmask_t *irq_get_used_vector_mask
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
+ else if ( IO_APIC_IRQ(irq) &&
|
||
|
+ opt_irq_vector_map != OPT_IRQ_VECTOR_MAP_NONE )
|
||
|
+ {
|
||
|
+ ret = io_apic_get_used_vector_map(irq);
|
||
|
+ }
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
--- a/xen/include/asm-x86/irq.h
|
||
|
+++ b/xen/include/asm-x86/irq.h
|
||
|
@@ -113,6 +113,7 @@ void setup_IO_APIC(void);
|
||
|
void disable_IO_APIC(void);
|
||
|
void print_IO_APIC(void);
|
||
|
void setup_ioapic_dest(void);
|
||
|
+vmask_t *io_apic_get_used_vector_map(unsigned int irq);
|
||
|
|
||
|
extern unsigned long io_apic_irqs;
|
||
|
|