Re: [patch] enabling APIC and NMI watchdog on UP systems

From: Mikael Pettersson (mikpe@csd.uu.se)
Date: Sun Oct 01 2000 - 16:30:14 EST


On Sat, 30 Sep 2000, Ingo Molnar wrote:

>
> On Sat, 30 Sep 2000, Keith Owens wrote:
>
> > via /dev/msr. On SMP you end up with two sources of NMI, local APIC
> > on every cpu plus IO-APIC. The code in linux/arch/i386/kernel/traps.c
> > resets PERFCTR1 on every NMI, [...]
>
> yep, thanks, thats a bug, i'll fix it.
>
> Ingo

The upapic-2.4.0-test9-C3 patch has another problem.

On Fri, 29 Sep 2000, Udo A. Steinberg wrote:

>I've been giving the patch a try, however it hangs my machine during boot.
>Here's the important bits from console:
>
>Local APIC disabled by BIOS -- reenabling
>found and enabled local APIC!
>
>It then locks up in Calibrating delay loop...

What's happening is that on boot, the APIC is disabled (so the
external interrupt pins bypass it) and its contents is in a "masked"
state. After toggling the enable flags in MSR 0x1B and APIC SPIV,
interrupts are routed via the APIC; however, the LVT entries are
still masked which prevents any interrupts from being delivered.
The symptom is a hang in calibrate_delay(). (Unless your UP BIOS
initialises the APIC to through-local mode, which is unlikely.)

Intialising the local APIC in the start_kernel() -> smp_init() ->
IO_APIC_init_uniprocessor() path is too late. The kernel needs
interrupts long before that.

My own patch for enabling the local APIC on UP enables it from
arch/i386/kernel/setup.c, immediately after init_apic_mappings().
I've attached a version of this patch which has been retrofitted
to work on top of Ingo's upapic-2.4.0-test9-C3 patch. With this,
my kernels boot and work ok (well, apart from not having perfctrs
any more 8-< ).

BTW, does anyone have any docs on the AMD K7's local APIC? The
K7 BIOS manual is supposed to document the local APIC, but it
doesn't appear to be available at their web site...

/Mikael

--- linux-2.4.0-test9-pre7-upapic/arch/i386/kernel/apic.c.~1~ Fri Sep 29 14:58:40 2000
+++ linux-2.4.0-test9-pre7-upapic/arch/i386/kernel/apic.c Sun Oct 1 21:53:46 2000
@@ -198,10 +198,16 @@
  * Original code written by Keir Fraser
  */
 
-int detect_init_APIC (void)
+static int __init detect_init_APIC (void)
 {
         u32 h, l, dummy, features;
 
+ if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) {
+ /* Does anyone outside AMD have docs for the K7 local APIC? */
+ printk("Cannot enable local APIC on non-Intel processors\n");
+ return -1;
+ }
+
         if (boot_cpu_data.x86 < 5) {
                 printk("No local APIC on pre-Pentium Intel processors\n");
                 return -1;
@@ -242,11 +248,82 @@
 }
 
 /*
+ * Initialize a P6's local APIC for UP operation (through-local).
+ * Assumes that init_apic_mappings() has mapped the local APIC.
+ * TODO: check how to do this for K7 and P4.
+ * Original code written by Mikael Pettersson.
+ */
+void __init init_local_APIC(void)
+{
+ unsigned int msr_orig_low, msr_orig_high;
+ unsigned int spiv_orig;
+ unsigned int lvr;
+ int init_done;
+ unsigned int value;
+
+ if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
+ return;
+ if (boot_cpu_data.x86 != 6)
+ return;
+ init_done = 0;
+ rdmsr(0x1B, msr_orig_low, msr_orig_high);
+ if (!(msr_orig_low & (1<<11))) {
+ wrmsr(0x1B, msr_orig_low|(1<<11), msr_orig_high);
+ printk(__FUNCTION__ ": enabled local APIC msr\n");
+ init_done = 1;
+ }
+ spiv_orig = apic_read(APIC_SPIV);
+ if (!(spiv_orig & (1<<8))) {
+ value = spiv_orig;
+ value &= ~APIC_VECTOR_MASK;
+ value |= (1<<8)|SPURIOUS_APIC_VECTOR;
+ apic_write(APIC_SPIV, value);
+ printk(__FUNCTION__ ": enabled local APIC SPIV\n");
+ init_done = 1;
+ }
+ /*
+ * Make sure the page map points to the real thing.
+ */
+ lvr = apic_read(APIC_LVR);
+ if (!APIC_INTEGRATED(lvr))
+ goto out_init;
+ if (GET_APIC_MAXLVT(lvr) != 4)
+ goto out_init;
+ /*
+ * Careful! Writing a zero vector to LVTT or LVTPC causes a
+ * 0x40 APIC error (Received Illegal Vector) even if the entry
+ * is masked. We therefore supply non-zero vectors below.
+ */
+ if (init_done) { /* on UP, we're the first to init it */
+ apic_write(APIC_LVT0, APIC_DM_EXTINT|APIC_LVT_LEVEL_TRIGGER);
+ apic_write(APIC_LVT1, APIC_DM_NMI);
+ apic_write(APIC_ESR, 0);
+ apic_read(APIC_ESR);
+ apic_read(APIC_LVTERR);
+ apic_write(APIC_LVTERR, ERROR_APIC_VECTOR);
+ apic_write(APIC_ESR, 0);
+ apic_read(APIC_ESR);
+ apic_write(APIC_LVTT, APIC_LVT_MASKED|LOCAL_TIMER_VECTOR);
+ }
+ apic_write(APIC_LVTPC, APIC_LVT_MASKED|ERROR_APIC_VECTOR);
+ boot_cpu_data.x86_capability |= X86_FEATURE_APIC;
+ printk(KERN_INFO "enabled P6 APIC\n");
+ return;
+
+ out_init:
+ if (init_done) {
+ apic_write(APIC_SPIV, spiv_orig);
+ wrmsr(0x1B, msr_orig_low, msr_orig_high);
+ printk(__FUNCTION__ ": disabled local APIC\n");
+ }
+}
+
+/*
  * Activate the NMI watchdog via the local APIC.
  * Original code written by Keith Owens.
  */
 
-static void setup_apic_nmi_watchdog (void)
+static void __init setup_apic_nmi_watchdog (void)
 {
         int value;
 
@@ -409,13 +486,14 @@
 void __init init_apic_mappings(void)
 {
         unsigned long apic_phys;
+ int kludge = -1;
 
         /*
          * If no local APIC can be found then set up a fake all
          * zeroes page to simulate the local APIC and another
          * one for the IO-APIC.
          */
- if (!smp_found_config && detect_init_APIC()) {
+ if (!smp_found_config && (kludge = detect_init_APIC()) < 0) {
                 apic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
                 apic_phys = __pa(apic_phys);
         } else
@@ -424,6 +502,18 @@
         set_fixmap_nocache(FIX_APIC_BASE, apic_phys);
         Dprintk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys);
 
+ if (kludge == 0)
+ init_local_APIC();
+ /*
+ * cpu_has_apic == (boot_cpu_data.x86_capability & X86_FEATURE_APIC)
+ * [see <asm-i386/processor.h>]
+ *
+ * so the if-statement below is:
+ * if (x && y) {
+ * ...
+ * y = 1; // why?
+ * }
+ */
         if (!smp_found_config && cpu_has_apic) {
                 /*
                  * Make sure that we are processor 0, and that we are indicated
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Sat Oct 07 2000 - 21:00:08 EST