i386/lapic: Handle the case that the CPU does not have LAPIC for SMP kernel
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Fri, 13 May 2011 03:26:32 +0000 (11:26 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Fri, 13 May 2011 08:39:42 +0000 (16:39 +0800)
If LAPIC does not exist:
- Reset apic_io_enable and reinitialize ICU if necessary; mainly for
  ICU's auto EOI setting.
- Setup minimum information for BSP's globaldata

While I'm here, add hw.lapic_enable tunable to test this feature (just don't
use it :).

sys/platform/pc32/apic/lapic.c
sys/platform/pc32/apic/lapic.h
sys/platform/pc32/i386/mp_machdep.c
sys/platform/pc32/icu/icu.c
sys/platform/pc32/icu/icu_var.h

index 9b989b3..ab76ba9 100644 (file)
@@ -647,24 +647,34 @@ lapic_map(vm_offset_t lapic_addr)
 static TAILQ_HEAD(, lapic_enumerator) lapic_enumerators =
        TAILQ_HEAD_INITIALIZER(lapic_enumerators);
 
-void
+int
 lapic_config(void)
 {
        struct lapic_enumerator *e;
-       int error, i;
+       int error, i, enable;
 
        for (i = 0; i < NAPICID; ++i)
                APICID_TO_CPUID(i) = -1;
 
+       enable = 1;
+       TUNABLE_INT_FETCH("hw.lapic_enable", &enable);
+       if (!enable) {
+               kprintf("LAPIC: Warning LAPIC is disabled\n");
+               return ENXIO;
+       }
+
        TAILQ_FOREACH(e, &lapic_enumerators, lapic_link) {
                error = e->lapic_probe(e);
                if (!error)
                        break;
        }
-       if (e == NULL)
-               panic("can't config lapic\n");
+       if (e == NULL) {
+               kprintf("LAPIC: Can't find LAPIC\n");
+               return ENXIO;
+       }
 
        e->lapic_enumerate(e);
+       return 0;
 }
 
 void
index 2271bbe..4b96bf0 100644 (file)
@@ -64,7 +64,7 @@ void  selected_apic_ipi(cpumask_t, int, int);
 void   single_apic_ipi(int, int, int);
 int    single_apic_ipi_passive(int, int, int);
 void   lapic_set_cpuid(int, int);
-void   lapic_config(void);
+int    lapic_config(void);
 void   lapic_enumerator_register(struct lapic_enumerator *);
 void   set_apic_timer(int);
 int    get_apic_timer_frequency(void);
index 7b427cc..b775d7e 100644 (file)
@@ -56,6 +56,7 @@
 #include <machine/atomic.h>
 #include <machine/cpufunc.h>
 #include <machine/cputypes.h>
+#include <machine_base/icu/icu_var.h>
 #include <machine_base/apic/ioapic_abi.h>
 #include <machine_base/apic/lapic.h>
 #include <machine_base/apic/ioapic.h>
@@ -177,6 +178,7 @@ static int  start_all_aps(u_int boot_addr);
 static void    install_ap_tramp(u_int boot_addr);
 static int     start_ap(struct mdglobaldata *gd, u_int boot_addr, int smibest);
 static int     smitest(void);
+static void    cpu_simple_setup(void);
 
 static cpumask_t smp_startup_mask = 1; /* which cpus have been started */
 static cpumask_t smp_lapic_mask = 1;   /* which cpus have lapic been inited */
@@ -313,9 +315,19 @@ init_secondary(void)
 static void
 mp_enable(u_int boot_addr)
 {
+       int error;
+
        POSTCODE(MP_ENABLE_POST);
 
-       lapic_config();
+       error = lapic_config();
+       if (error) {
+               if (apic_io_enable) {
+                       apic_io_enable = 0;
+                       icu_reinit_noioapic();
+               }
+               cpu_simple_setup();
+               return;
+       }
 
        /* Initialize BSP's local APIC */
        lapic_init(TRUE);
@@ -1110,3 +1122,17 @@ cpu_send_ipiq_passive(int dcpu)
        return(r);
 }
 #endif
+
+static void
+cpu_simple_setup(void)
+{
+       /* build our map of 'other' CPUs */
+       mycpu->gd_other_cpus = smp_startup_mask & ~CPUMASK(mycpu->gd_cpuid);
+       mycpu->gd_ipiq = (void *)kmem_alloc(&kernel_map, sizeof(lwkt_ipiq) * ncpus);
+       bzero(mycpu->gd_ipiq, sizeof(lwkt_ipiq) * ncpus);
+
+       pmap_set_opt();
+
+       if (cpu_feature & CPUID_TSC)
+               tsc0_offset = rdtsc();
+}
index 3cec0c0..a7c12f3 100644 (file)
@@ -50,6 +50,7 @@
 #include <sys/systm.h>
 #include <sys/machintr.h>
 #include <sys/interrupt.h>
+#include <sys/thread2.h>
 #include <bus/isa/isareg.h>
 #include <cpu/cpufunc.h>
 #include <machine/smp.h>
@@ -180,3 +181,32 @@ icu_ioapic_extint(int irq, int vec)
 
        return 0;
 }
+
+#ifdef SMP
+
+void
+icu_reinit_noioapic(void)
+{
+       u_long ef;
+
+       KKASSERT(MachIntrABI.type == MACHINTR_ICU);
+       KKASSERT(apic_io_enable == 0);
+
+       crit_enter();
+       ef = read_eflags();
+       cpu_disable_intr();
+
+       /* Leave interrupts masked */
+       outb(IO_ICU1 + ICU_IMR_OFFSET, 0xff);
+       outb(IO_ICU2 + ICU_IMR_OFFSET, 0xff);
+
+       icu_init();
+       MachIntrABI.stabilize();
+
+       write_eflags(ef);
+
+       MachIntrABI.cleanup();
+       crit_exit();
+}
+
+#endif
index 397f269..47e046c 100644 (file)
@@ -40,6 +40,9 @@
 
 void           icu_definit(void);
 void           icu_reinit(void);
+#ifdef SMP
+void           icu_reinit_noioapic(void);
+#endif
 
 intrmask_t     icu_irq_pending(void);