800917b5a2
- Update to Xen 4.1.2_rc2 c/s 23152 - bnc#716695 - domUs using tap devices will not start updated multi-xvdp.patch - Upstream patches from Jan 23803-intel-pmu-models.patch 23800-x86_64-guest-addr-range.patch 23795-intel-ich10-quirk.patch 23804-x86-IPI-counts.patch - bnc#706106 - Inconsistent reporting of VM names during migration xend-migration-domname-fix.patch - bnc#712823 - L3:Xen guest does not start reliable when rebooted xend-vcpu-affinity-fix.patch OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=143
200 lines
6.7 KiB
Diff
200 lines
6.7 KiB
Diff
# HG changeset patch
|
|
# User Andrew Cooper <andrew.cooper3@citrix.com>
|
|
# Date 1315906390 -3600
|
|
# Node ID ffe8e65f6687cde49b2cb2bf991bd3f5dff9c189
|
|
# Parent ad3b4bb097cb6308f73e597c5412395ad783ea4a
|
|
IRQ: IO-APIC support End Of Interrupt for older IO-APICs
|
|
|
|
The old io_apic_eoi() function using the EOI register only works for
|
|
IO-APICs with a version of 0x20. Older IO-APICs do not have an EOI
|
|
register so line level interrupts have to be EOI'd by flipping the
|
|
mode to edge and back, which clears the IRR and Delivery Status bits.
|
|
|
|
This patch replaces the current io_apic_eoi() function with one which
|
|
takes into account the version of the IO-APIC and EOI's
|
|
appropriately.
|
|
|
|
v2: make recursive call to __io_apic_eoi() to reduce code size.
|
|
|
|
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
|
|
|
--- a/xen/arch/x86/io_apic.c
|
|
+++ b/xen/arch/x86/io_apic.c
|
|
@@ -66,6 +66,13 @@ int __read_mostly nr_ioapics;
|
|
#define MAX_PLUS_SHARED_IRQS nr_irqs_gsi
|
|
#define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + nr_irqs_gsi)
|
|
|
|
+
|
|
+#define ioapic_has_eoi_reg(apic) (mp_ioapics[(apic)].mpc_apicver >= 0x20)
|
|
+
|
|
+#define io_apic_eoi_vector(apic, vector) io_apic_eoi((apic), (vector), -1)
|
|
+#define io_apic_eoi_pin(apic, pin) io_apic_eoi((apic), -1, (pin))
|
|
+
|
|
+
|
|
/*
|
|
* This is performance-critical, we want to do it O(1)
|
|
*
|
|
@@ -201,6 +208,105 @@ static void ioapic_write_entry(int apic,
|
|
spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
}
|
|
|
|
+/* EOI an IO-APIC entry. One of vector or pin may be -1, indicating that
|
|
+ * it should be worked out using the other. This function expect that the
|
|
+ * ioapic_lock is taken, and interrupts are disabled (or there is a good reason
|
|
+ * not to), and that if both pin and vector are passed, that they refer to the
|
|
+ * same redirection entry in the IO-APIC. */
|
|
+static void __io_apic_eoi(unsigned int apic, unsigned int vector, unsigned int pin)
|
|
+{
|
|
+ /* Ensure some useful information is passed in */
|
|
+ BUG_ON( (vector == -1 && pin == -1) );
|
|
+
|
|
+ /* Prefer the use of the EOI register if available */
|
|
+ if ( ioapic_has_eoi_reg(apic) )
|
|
+ {
|
|
+ /* If vector is unknown, read it from the IO-APIC */
|
|
+ if ( vector == -1 )
|
|
+ vector = __ioapic_read_entry(apic, pin, TRUE).vector;
|
|
+
|
|
+ *(IO_APIC_BASE(apic)+16) = vector;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /* Else fake an EOI by switching to edge triggered mode
|
|
+ * and back */
|
|
+ struct IO_APIC_route_entry entry;
|
|
+ bool_t need_to_unmask = 0;
|
|
+
|
|
+ /* If pin is unknown, search for it */
|
|
+ if ( pin == -1 )
|
|
+ {
|
|
+ unsigned int p;
|
|
+ for ( p = 0; p < nr_ioapic_registers[apic]; ++p )
|
|
+ {
|
|
+ entry = __ioapic_read_entry(apic, p, TRUE);
|
|
+ if ( entry.vector == vector )
|
|
+ {
|
|
+ pin = p;
|
|
+ /* break; */
|
|
+
|
|
+ /* Here should be a break out of the loop, but at the
|
|
+ * Xen code doesn't actually prevent multiple IO-APIC
|
|
+ * entries being assigned the same vector, so EOI all
|
|
+ * pins which have the correct vector.
|
|
+ *
|
|
+ * Remove the following code when the above assertion
|
|
+ * is fulfilled. */
|
|
+ __io_apic_eoi(apic, vector, p);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* If search fails, nothing to do */
|
|
+
|
|
+ /* if ( pin == -1 ) */
|
|
+
|
|
+ /* Because the loop wasn't broken out of (see comment above),
|
|
+ * all relevant pins have been EOI, so we can always return.
|
|
+ *
|
|
+ * Re-instate the if statement above when the Xen logic has been
|
|
+ * fixed.*/
|
|
+
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ entry = __ioapic_read_entry(apic, pin, TRUE);
|
|
+
|
|
+ if ( ! entry.mask )
|
|
+ {
|
|
+ /* If entry is not currently masked, mask it and make
|
|
+ * a note to unmask it later */
|
|
+ entry.mask = 1;
|
|
+ __ioapic_write_entry(apic, pin, TRUE, entry);
|
|
+ need_to_unmask = 1;
|
|
+ }
|
|
+
|
|
+ /* Flip the trigger mode to edge and back */
|
|
+ entry.trigger = 0;
|
|
+ __ioapic_write_entry(apic, pin, TRUE, entry);
|
|
+ entry.trigger = 1;
|
|
+ __ioapic_write_entry(apic, pin, TRUE, entry);
|
|
+
|
|
+ if ( need_to_unmask )
|
|
+ {
|
|
+ /* Unmask if neccesary */
|
|
+ entry.mask = 0;
|
|
+ __ioapic_write_entry(apic, pin, TRUE, entry);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/* EOI an IO-APIC entry. One of vector or pin may be -1, indicating that
|
|
+ * it should be worked out using the other. This function disables interrupts
|
|
+ * and takes the ioapic_lock */
|
|
+static void io_apic_eoi(unsigned int apic, unsigned int vector, unsigned int pin)
|
|
+{
|
|
+ unsigned int flags;
|
|
+ spin_lock_irqsave(&ioapic_lock, flags);
|
|
+ __io_apic_eoi(apic, vector, pin);
|
|
+ spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
+}
|
|
+
|
|
/*
|
|
* Saves all the IO-APIC RTE's
|
|
*/
|
|
@@ -350,7 +456,7 @@ static void __eoi_IO_APIC_irq(unsigned i
|
|
pin = entry->pin;
|
|
if (pin == -1)
|
|
break;
|
|
- io_apic_eoi(entry->apic, vector);
|
|
+ __io_apic_eoi(entry->apic, vector, pin);
|
|
if (!entry->next)
|
|
break;
|
|
entry = irq_2_pin + entry->next;
|
|
@@ -390,18 +496,7 @@ static void clear_IO_APIC_pin(unsigned i
|
|
entry.trigger = 1;
|
|
__ioapic_write_entry(apic, pin, TRUE, entry);
|
|
}
|
|
- if (mp_ioapics[apic].mpc_apicver >= 0x20)
|
|
- io_apic_eoi(apic, entry.vector);
|
|
- else {
|
|
- /*
|
|
- * Mechanism by which we clear remoteIRR in this case is by
|
|
- * changing the trigger mode to edge and back to level.
|
|
- */
|
|
- entry.trigger = 0;
|
|
- __ioapic_write_entry(apic, pin, TRUE, entry);
|
|
- entry.trigger = 1;
|
|
- __ioapic_write_entry(apic, pin, TRUE, entry);
|
|
- }
|
|
+ __io_apic_eoi(apic, entry.vector, pin);
|
|
}
|
|
|
|
/*
|
|
@@ -1731,7 +1826,7 @@ static void end_level_ioapic_irq (unsign
|
|
{
|
|
int ioapic;
|
|
for (ioapic = 0; ioapic < nr_ioapics; ioapic++)
|
|
- io_apic_eoi(ioapic, i);
|
|
+ io_apic_eoi_vector(ioapic, i);
|
|
}
|
|
|
|
v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));
|
|
@@ -2604,3 +2699,4 @@ void __init init_ioapic_mappings(void)
|
|
printk(XENLOG_INFO "IRQ limits: %u GSI, %u MSI/MSI-X\n",
|
|
nr_irqs_gsi, nr_irqs - nr_irqs_gsi);
|
|
}
|
|
+
|
|
--- a/xen/include/asm-x86/io_apic.h
|
|
+++ b/xen/include/asm-x86/io_apic.h
|
|
@@ -157,11 +157,6 @@ static inline void io_apic_write(unsigne
|
|
__io_apic_write(apic, reg, value);
|
|
}
|
|
|
|
-static inline void io_apic_eoi(unsigned int apic, unsigned int vector)
|
|
-{
|
|
- *(IO_APIC_BASE(apic)+16) = vector;
|
|
-}
|
|
-
|
|
/*
|
|
* Re-write a value: to be used for read-modify-write
|
|
* cycles where the read already set up the index register.
|