[PATCH] local APIC support on uniprocessor machines

From: Keir Fraser (Keir.Fraser@cl.cam.ac.uk)
Date: Sun Aug 13 2000 - 08:59:46 EST


Despite selecting the "APIC and IO-APIC support on uniprocessors"
kernel config option, I've had trouble getting 2.4.0-test6 to
correctly enable the local APIC.

It turns out there are two problems (at least on my machine :-):

 * My BIOS appears to disable the APIC completely (by writing to the
   APIC_BASE MSR), causing CPUID to claim there is no local APIC.

 * Linux requires the BIOS to provide multiprocessor setup information,
   or it will simply ignore the APICs (presumably because it does not
   know where the IO-APICs reside unless the BIOS tells it). I'm not
   sure whether uniprocessor chipsets provide an IO-APIC anyway.

Since I require local APIC (but not IO-APIC) functionality to get
exceptions from the per-processor performance counters, I've appended
a patch to this mail which fixes the problem for linux-2.4.0-test6.

 -- Keir Fraser

PS. Please "reply-all" as I don't subscribe to this list!

diff -urBP origtest6/arch/i386/kernel/apic.c newtest6/arch/i386/kernel/apic.c
--- origtest6/arch/i386/kernel/apic.c Sun Aug 13 14:24:40 2000
+++ newtest6/arch/i386/kernel/apic.c Sun Aug 13 14:24:53 2000
@@ -267,18 +267,16 @@
 {
         unsigned long apic_phys;
 
- if (smp_found_config) {
- apic_phys = mp_lapic_addr;
- } else {
- /*
- * set up a fake all zeroes page to simulate the
- * local APIC and another one for the IO-APIC. We
- * could use the real zero-page, but it's safer
- * this way if some buggy code writes to this page ...
- */
- apic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
- apic_phys = __pa(apic_phys);
- }
+ /*
+ * Now that we make more of an effort to enable the local APIC even
+ * when we could find no SMP config information, we always map the
+ * APIC registers correctly (ie. the zero-page trick has been
+ * removed). See `IO_APIC_init_uniprocessor' in io_apic.c for more
+ * info.
+ */
+ if ( !smp_found_config ) mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
+ apic_phys = mp_lapic_addr;
+
         set_fixmap_nocache(FIX_APIC_BASE, apic_phys);
         Dprintk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys);
 
diff -urBP origtest6/arch/i386/kernel/io_apic.c newtest6/arch/i386/kernel/io_apic.c
--- origtest6/arch/i386/kernel/io_apic.c Sun Aug 13 14:24:45 2000
+++ newtest6/arch/i386/kernel/io_apic.c Sun Aug 13 14:24:57 2000
@@ -1518,11 +1518,60 @@
  */
 void IO_APIC_init_uniprocessor (void)
 {
+ /*
+ * For real non-SMP machines, we now make more of an effort to
+ * actually enable the local APIC. We do this without enabling any IO
+ * APICs (without smp_config info we don't know if there are any!).
+ */
         if (!smp_found_config)
- return;
+ {
+ u32 h, l, dummy, features;
+
+ /* Some BIOSes disable the local APIC in the APIC_BASE MSR */
+ rdmsr(0x1b, l, h);
+ if ( !(l & 0x800) )
+ {
+ printk("Local APIC disabled by BIOS -- reenabling...\n");
+ l |= 0x800;
+ wrmsr(0x1b, l, h);
+
+ /* The APIC feature bit should now be enabled in `cpuid' */
+ cpuid(1, &dummy, &dummy, &dummy, &features);
+ boot_cpu_data.x86_capability |= features & X86_FEATURE_APIC;
+ }
+
+ /*
+ * Make sure that we are processor 0, and that we are indicated
+ * as present. This stuff doesn't normally get done on a
+ * uniprocessor machine.
+ */
+ phys_cpu_present_map = 1;
+ apic_write_around(APIC_ID, 0);
+
+ /*
+ * Not sure about this, but it stops external INTs being masked!
+ * This is necessary because we don't initialise any IO APICs:
+ * (a) they weren't memory-mapped by `init_apic_mappings' because
+ * it didn't find any smp configuration info.
+ * (b) in a uniprocessor system, an IO APIC is redundant because
+ * all external INTs must go to the only processor.
+ */
+ pic_mode = 1;
+ nr_ioapics = 0;
+ }
+
         connect_bsp_APIC();
         setup_local_APIC();
- setup_IO_APIC();
- setup_APIC_clocks();
+
+ /*
+ * We only set up IO APICs for a real SMP machine. Otherwise external
+ * INTs get masked locally, without them being routed to an IO APIC.
+ */
+ if ( smp_found_config )
+ {
+ setup_IO_APIC();
+ }
+
+ setup_APIC_clocks();
 }
 #endif

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Tue Aug 15 2000 - 21:00:30 EST