# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1258959499 0
# Node ID 522ae754787d678ad64fcad7ee951bdce4fe28ce
# Parent 3ca45272ff2cf8382d324d2ef767f1fe9e3022e3
x86: enable directed EOI
This patch enables directed EOI on latest processor. With this, the
broadcast of EOI would be suppressed upon LAPIC EOI, so VMM is
required to perform a directed EOI to the IOxAPIC generating the
interrupt by writting to its EOI register.(Pls. refer SDM 3A 10.5.5)
This is useful for ioapic_ack_old to avoid the spurious interrupt
storm, which is the reason why ioapic_ack_new is used.
Signed-Off-By: Zhai Edwin <edwin.zhai@xxxxxxxxx>
---
xen/arch/x86/apic.c | 25 +++++++++++++++++++++++++
xen/arch/x86/io_apic.c | 35 +++++++++++++++++++++++++++++++++--
xen/include/asm-x86/apic.h | 1 +
xen/include/asm-x86/apicdef.h | 2 ++
xen/include/asm-x86/io_apic.h | 5 +++++
5 files changed, 66 insertions(+), 2 deletions(-)
diff -r 3ca45272ff2c -r 522ae754787d xen/arch/x86/apic.c
--- a/xen/arch/x86/apic.c Mon Nov 23 06:56:01 2009 +0000
+++ b/xen/arch/x86/apic.c Mon Nov 23 06:58:19 2009 +0000
@@ -68,6 +68,7 @@ int apic_verbosity;
int apic_verbosity;
int x2apic_enabled __read_mostly = 0;
+int directed_eoi_enabled __read_mostly = 0;
/*
* The following vectors are part of the Linux architecture, there
@@ -348,6 +349,7 @@ void disable_local_APIC(void)
}
}
+extern int ioapic_ack_new;
/*
* This is to verify that we're looking at a real local APIC.
* Check these against your board if the CPUs aren't getting
@@ -386,6 +388,18 @@ int __init verify_local_APIC(void)
reg1 = get_maxlvt();
if (reg1 < 0x02 || reg1 == 0xff)
return 0;
+
+ /*
+ * Detecting directed EOI on BSP:
+ * If having directed EOI support in lapic, force to use ioapic_ack_old,
+ * and enable the directed EOI for intr handling.
+ */
+ if ( reg0 & APIC_LVR_DIRECTED_EOI )
+ {
+ ioapic_ack_new = 0;
+ directed_eoi_enabled = 1;
+ printk("Enabled directed EOI with ioapic_ack_old on!\n");
+ }
/*
* The ID register is read/write in a real APIC.
@@ -575,6 +589,17 @@ void __devinit setup_local_APIC(void)
* Set spurious IRQ vector
*/
value |= SPURIOUS_APIC_VECTOR;
+
+ /*
+ * Enable directed EOI
+ */
+ if ( directed_eoi_enabled )
+ {
+ value |= APIC_SPIV_DIRECTED_EOI;
+ apic_printk(APIC_VERBOSE, "Suppress EOI broadcast on CPU#%d\n",
+ smp_processor_id());
+ }
+
apic_write_around(APIC_SPIV, value);
/*
diff -r 3ca45272ff2c -r 522ae754787d xen/arch/x86/io_apic.c
--- a/xen/arch/x86/io_apic.c Mon Nov 23 06:56:01 2009 +0000
+++ b/xen/arch/x86/io_apic.c Mon Nov 23 06:58:19 2009 +0000
@@ -194,6 +194,30 @@ static void unmask_IO_APIC_irq (unsigned
spin_lock_irqsave(&ioapic_lock, flags);
__unmask_IO_APIC_irq(irq);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+}
+
+static void __eoi_IO_APIC_irq(unsigned int irq)
+{
+ struct irq_pin_list *entry = irq_2_pin + irq;
+ unsigned int pin, vector = IO_APIC_VECTOR(irq);
+
+ for (;;) {
+ pin = entry->pin;
+ if (pin == -1)
+ break;
+ io_apic_eoi(entry->apic, vector);
+ if (!entry->next)
+ break;
+ entry = irq_2_pin + entry->next;
+ }
+}
+
+static void eoi_IO_APIC_irq(unsigned int irq)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&ioapic_lock, flags);
+ __eoi_IO_APIC_irq(irq);
spin_unlock_irqrestore(&ioapic_lock, flags);
}
@@ -1464,7 +1488,8 @@ static void mask_and_ack_level_ioapic_ir
if ( ioapic_ack_new )
return;
- mask_IO_APIC_irq(irq);
+ if ( !directed_eoi_enabled )
+ mask_IO_APIC_irq(irq);
/*
* It appears there is an erratum which affects at least version 0x11
@@ -1511,8 +1536,14 @@ static void end_level_ioapic_irq (unsign
if ( !ioapic_ack_new )
{
- if ( !(irq_desc[irq].status & IRQ_DISABLED) )
+ if ( irq_desc[irq].status & IRQ_DISABLED )
+ return;
+
+ if ( directed_eoi_enabled )
+ eoi_IO_APIC_irq(irq);
+ else
unmask_IO_APIC_irq(irq);
+
return;
}
diff -r 3ca45272ff2c -r 522ae754787d xen/include/asm-x86/apic.h
--- a/xen/include/asm-x86/apic.h Mon Nov 23 06:56:01 2009 +0000
+++ b/xen/include/asm-x86/apic.h Mon Nov 23 06:58:19 2009 +0000
@@ -23,6 +23,7 @@
extern int apic_verbosity;
extern int x2apic_enabled;
+extern int directed_eoi_enabled;
extern void enable_x2apic(void);
diff -r 3ca45272ff2c -r 522ae754787d xen/include/asm-x86/apicdef.h
--- a/xen/include/asm-x86/apicdef.h Mon Nov 23 06:56:01 2009 +0000
+++ b/xen/include/asm-x86/apicdef.h Mon Nov 23 06:58:19 2009 +0000
@@ -16,6 +16,7 @@
#define SET_xAPIC_ID(x) (((x)<<24))
#define APIC_LVR 0x30
#define APIC_LVR_MASK 0xFF00FF
+#define APIC_LVR_DIRECTED_EOI (1 << 24)
#define GET_APIC_VERSION(x) ((x)&0xFF)
#define GET_APIC_MAXLVT(x) (((x)>>16)&0xFF)
#define APIC_INTEGRATED(x) ((x)&0xF0)
@@ -39,6 +40,7 @@
#define APIC_SPIV 0xF0
#define APIC_SPIV_FOCUS_DISABLED (1<<9)
#define APIC_SPIV_APIC_ENABLED (1<<8)
+#define APIC_SPIV_DIRECTED_EOI (1<<12)
#define APIC_ISR 0x100
#define APIC_ISR_NR 0x8 /* Number of 32 bit ISR registers. */
#define APIC_TMR 0x180
diff -r 3ca45272ff2c -r 522ae754787d xen/include/asm-x86/io_apic.h
--- a/xen/include/asm-x86/io_apic.h Mon Nov 23 06:56:01 2009 +0000
+++ b/xen/include/asm-x86/io_apic.h Mon Nov 23 06:58:19 2009 +0000
@@ -147,6 +147,11 @@ static inline void io_apic_write(unsigne
*(IO_APIC_BASE(apic)+4) = 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.
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|