ChangeSet 1.1308, 2005/04/16 00:40:59+01:00, iap10@xxxxxxxxxxxxxxxxxxxxx
The attached patch apic.patch updates xen/arch/x86/apic.c so that it is
based on linux 2.6.10 code. A few changes made to linux required reworking
functions in other files as well so I held off on those changes. For example,
setup_APIC_timer(void *) changed to setup_APIC_timer(unsigned int). The change
has no real bearing on the Xen code -- it's just a question of how close to
linux one wants to be. However, that change goes with a change to
smp_call_function which would affect quite a few other files/functions so I
left it as is. Most of the other changes are trivial.
xen/ac_timer.h was included but not needed by apic.c so I removed it
from the list of #includes.
The new apic.c includes two new files: asm/io_ports.h and
asm/mach_apic.h. Patches to create those files are included as well.
arch/x86/apic.c | 372 +++++++++++++++++++++++++++++++-------------
include/asm-x86/io_ports.h | 30 +++
include/asm-x86/mach_apic.h | 32 +++
3 files changed, 327 insertions(+), 107 deletions(-)
diff -Nru a/xen/arch/x86/apic.c b/xen/arch/x86/apic.c
--- a/xen/arch/x86/apic.c 2005-04-18 21:03:10 -04:00
+++ b/xen/arch/x86/apic.c 2005-04-18 21:03:10 -04:00
@@ -1,4 +1,6 @@
/*
+ * based on linux-2.6.10/arch/i386/kernel/apic.c
+ *
* Local APIC handling, local APIC timers
*
* (c) 1999, 2000 Ingo Molnar <mingo@xxxxxxxxxx>
@@ -10,11 +12,11 @@
* for testing these extensively.
* Maciej W. Rozycki : Various updates and fixes.
* Mikael Pettersson : Power Management for UP-APIC.
+ * Pavel Machek and
+ * Mikael Pettersson : PM converted to driver model.
*/
-
#include <xen/config.h>
-#include <xen/ac_timer.h>
#include <xen/perfc.h>
#include <xen/errno.h>
#include <xen/init.h>
@@ -32,7 +34,8 @@
#include <asm/hardirq.h>
#include <asm/apic.h>
#include <asm/io_apic.h>
-
+#include <asm/mach_apic.h>
+#include <asm/io_ports.h>
/* Using APIC to generate smp_local_timer_interrupt? */
int using_apic_timer = 0;
@@ -80,6 +83,16 @@
apic_write_around(APIC_LVTPC, v | APIC_LVT_MASKED);
}
+#if 0
+/* lets not touch this if we didn't frob it */
+#ifdef CONFIG_X86_MCE_P4THERMAL
+ if (maxlvt >= 5) {
+ v = apic_read(APIC_LVTTHMR);
+ apic_write_around(APIC_LVTTHMR, v | APIC_LVT_MASKED);
+ }
+#endif
+#endif
+
/*
* Clean APIC state for other OSs:
*/
@@ -90,9 +103,17 @@
apic_write_around(APIC_LVTERR, APIC_LVT_MASKED);
if (maxlvt >= 4)
apic_write_around(APIC_LVTPC, APIC_LVT_MASKED);
+
+#if 0
+#ifdef CONFIG_X86_MCE_P4THERMAL
+ if (maxlvt >= 5)
+ apic_write_around(APIC_LVTTHMR, APIC_LVT_MASKED);
+#endif
+#endif
+
v = GET_APIC_VERSION(apic_read(APIC_LVR));
if (APIC_INTEGRATED(v)) { /* !82489DX */
- if (maxlvt > 3)
+ if (maxlvt > 3) /* Due to Pentium errata 3AP and 11AP. */
apic_write(APIC_ESR, 0);
apic_read(APIC_ESR);
}
@@ -113,6 +134,9 @@
outb(0x70, 0x22);
outb(0x01, 0x23);
}
+#if 0
+ enable_apic_mode();
+#endif
}
void disconnect_bsp_APIC(void)
@@ -193,12 +217,6 @@
*/
reg0 = apic_read(APIC_ID);
Dprintk("Getting ID: %x\n", reg0);
- apic_write(APIC_ID, reg0 ^ APIC_ID_MASK);
- reg1 = apic_read(APIC_ID);
- Dprintk("Getting ID: %x\n", reg1);
- apic_write(APIC_ID, reg0);
- if (reg1 != (reg0 ^ APIC_ID_MASK))
- return 0;
/*
* The next two are just to see if we have sane values.
@@ -215,6 +233,10 @@
void __init sync_Arb_IDs(void)
{
+ /* Unsupported on P4 - see Intel Dev. Manual Vol. 3, Ch. 8.6.1 */
+ unsigned int ver = GET_APIC_VERSION(apic_read(APIC_LVR));
+ if (ver >= 0x14) /* P4 or higher */
+ return;
/*
* Wait for idle.
*/
@@ -240,15 +262,17 @@
{
}
-static unsigned long calculate_ldr(unsigned long old)
-{
- unsigned long id = 1UL << smp_processor_id();
- return (old & ~APIC_LDR_MASK)|SET_APIC_LOGICAL_ID(id);
-}
-
void __init setup_local_APIC (void)
{
- unsigned long value, ver, maxlvt;
+ unsigned long oldvalue, value, ver, maxlvt;
+
+ /* Pound the ESR really hard over the head with a big hammer - mbligh */
+ if (esr_disable) {
+ apic_write(APIC_ESR, 0);
+ apic_write(APIC_ESR, 0);
+ apic_write(APIC_ESR, 0);
+ apic_write(APIC_ESR, 0);
+ }
value = apic_read(APIC_LVR);
ver = GET_APIC_VERSION(value);
@@ -256,8 +280,10 @@
if ((SPURIOUS_APIC_VECTOR & 0x0f) != 0x0f)
__error_in_apic_c();
- /* Double-check wether this APIC is really registered. */
- if (!test_bit(GET_APIC_ID(apic_read(APIC_ID)), &phys_cpu_present_map))
+ /*
+ * Double-check whether this APIC is really registered.
+ */
+ if (!apic_id_registered())
BUG();
/*
@@ -265,19 +291,7 @@
* an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel
* document number 292116). So here it goes...
*/
-
- /*
- * In clustered apic mode, the firmware does this for us
- * Put the APIC into flat delivery mode.
- * Must be "all ones" explicitly for 82489DX.
- */
- apic_write_around(APIC_DFR, APIC_DFR_FLAT);
-
- /*
- * Set up the logical destination ID.
- */
- value = apic_read(APIC_LDR);
- apic_write_around(APIC_LDR, calculate_ldr(value));
+ init_apic_ldr();
/*
* Set Task Priority to 'accept all'. We never change this
@@ -297,10 +311,35 @@
*/
value |= APIC_SPIV_APIC_ENABLED;
+ /*
+ * Some unknown Intel IO/APIC (or APIC) errata is biting us with
+ * certain networking cards. If high frequency interrupts are
+ * happening on a particular IOAPIC pin, plus the IOAPIC routing
+ * entry is masked/unmasked at a high rate as well then sooner or
+ * later IOAPIC line gets 'stuck', no more interrupts are received
+ * from the device. If focus CPU is disabled then the hang goes
+ * away, oh well :-(
+ *
+ * [ This bug can be reproduced easily with a level-triggered
+ * PCI Ne2000 networking cards and PII/PIII processors, dual
+ * BX chipset. ]
+ */
+ /*
+ * Actually disabling the focus CPU check just makes the hang less
+ * frequent as it makes the interrupt distributon model be more
+ * like LRU than MRU (the short-term load is more even across CPUs).
+ * See also the comment in end_level_ioapic_irq(). --macro
+ */
+#if 1
/* Enable focus processor (bit==0) */
value &= ~APIC_SPIV_FOCUS_DISABLED;
-
- /* Set spurious IRQ vector */
+#else
+ /* Disable focus processor (bit==1) */
+ value |= APIC_SPIV_FOCUS_DISABLED;
+#endif
+ /*
+ * Set spurious IRQ vector
+ */
value |= SPURIOUS_APIC_VECTOR;
apic_write_around(APIC_SPIV, value);
@@ -315,7 +354,7 @@
* TODO: set up through-local-APIC from through-I/O-APIC? --macro
*/
value = apic_read(APIC_LVT0) & APIC_LVT_MASKED;
- if (!smp_processor_id()) {
+ if (!smp_processor_id() && (pic_mode || !value)) {
value = APIC_DM_EXTINT;
printk("enabled ExtINT on CPU#%d\n", smp_processor_id());
} else {
@@ -335,33 +374,43 @@
value |= APIC_LVT_LEVEL_TRIGGER;
apic_write_around(APIC_LVT1, value);
- if (APIC_INTEGRATED(ver)) { /* !82489DX */
+ if (APIC_INTEGRATED(ver) && !esr_disable) { /* !82489DX */
maxlvt = get_maxlvt();
if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */
apic_write(APIC_ESR, 0);
- value = apic_read(APIC_ESR);
- printk("ESR value before enabling vector: %08lx\n", value);
+ oldvalue = apic_read(APIC_ESR);
- value = ERROR_APIC_VECTOR; /* enables sending errors */
+ value = ERROR_APIC_VECTOR; // enables sending errors
apic_write_around(APIC_LVTERR, value);
- /* spec says clear errors after enabling vector. */
+ /*
+ * spec says clear errors after enabling vector.
+ */
if (maxlvt > 3)
apic_write(APIC_ESR, 0);
value = apic_read(APIC_ESR);
- printk("ESR value after enabling vector: %08lx\n", value);
+ if (value != oldvalue)
+ printk("ESR value before enabling vector: 0x%08lx "
+ "after: 0x%08lx\n", oldvalue, value);
} else {
+ if (esr_disable)
+ /*
+ * Something untraceble is creating bad interrupts on
+ * secondary quads ... for the moment, just leave the
+ * ESR disabled - we can't do anything useful with the
+ * errors anyway - mbligh
+ */
+ printk("Leaving ESR disabled.\n");
+ else
printk("No ESR for 82489DX.\n");
}
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|