aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@suse.com>2012-03-08 10:04:22 +0000
committerJan Beulich <jbeulich@suse.com>2012-03-08 10:04:22 +0000
commitec12f153900df268fc052a6e4cae5859dbaa7bea (patch)
treedaa8ee62956388595dbaf05579afcdcf3cf8c030
parent1c0aedadd29c085e905520e11234c948fb36a859 (diff)
downloadxen-ec12f153900df268fc052a6e4cae5859dbaa7bea.tar.gz
xen-ec12f153900df268fc052a6e4cae5859dbaa7bea.tar.bz2
xen-ec12f153900df268fc052a6e4cae5859dbaa7bea.zip
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> xen-unstable changeset: 24156:f29b5bd6e25f xen-unstable date: Fri Nov 18 09:21:24 2011 +0100
-rw-r--r--xen/arch/x86/io_apic.c55
-rw-r--r--xen/arch/x86/irq.c5
-rw-r--r--xen/include/asm-x86/irq.h1
3 files changed, 59 insertions, 2 deletions
diff --git a/xen/arch/x86/io_apic.c b/xen/arch/x86/io_apic.c
index b22c3936c8..e6b623ed32 100644
--- a/xen/arch/x86/io_apic.c
+++ b/xen/arch/x86/io_apic.c
@@ -70,6 +70,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)
*
@@ -110,6 +138,7 @@ static void add_pin_to_irq(unsigned int irq, int apic, int pin)
}
entry->apic = apic;
entry->pin = pin;
+ share_vector_maps(irq_2_pin[irq].apic, apic);
}
/*
@@ -125,6 +154,7 @@ static void __init replace_pin_at_irq(unsigned int irq,
if (entry->apic == oldapic && entry->pin == oldpin) {
entry->apic = newapic;
entry->pin = newpin;
+ share_vector_maps(oldapic, newapic);
}
if (!entry->next)
break;
@@ -132,6 +162,16 @@ static void __init replace_pin_at_irq(unsigned int irq,
}
}
+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;
@@ -1294,6 +1334,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 */
@@ -2465,13 +2517,12 @@ int ioapic_guest_write(unsigned long physbase, unsigned int reg, u32 val)
}
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);
diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c
index ead35c6ac4..c54f0bc4ba 100644
--- a/xen/arch/x86/irq.c
+++ b/xen/arch/x86/irq.c
@@ -403,6 +403,11 @@ static vmask_t *irq_get_used_vector_mask(int irq)
}
}
}
+ 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;
}
diff --git a/xen/include/asm-x86/irq.h b/xen/include/asm-x86/irq.h
index e6111a5871..59a786028e 100644
--- 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;