]> Zhao Yanbai Git Server - minix.git/commitdiff
SMP - BSP waits until the APs finish their booting
authorTomas Hruby <tom@minix3.org>
Wed, 15 Sep 2010 14:10:12 +0000 (14:10 +0000)
committerTomas Hruby <tom@minix3.org>
Wed, 15 Sep 2010 14:10:12 +0000 (14:10 +0000)
- APs configure local timers

- while configuring local APIC timer the CPUs fiddle with the interrupt
  handlers. As the interrupt table is shared the BSP must not run

kernel/arch/i386/apic.c
kernel/arch/i386/arch_smp.c
kernel/arch/i386/include/arch_proto.h
kernel/arch/i386/klib.S
kernel/arch/i386/memory.c
kernel/kernel.h
kernel/smp.c
kernel/smp.h

index 979325be2a768fad6bbbbb05ca553695bc56b7b1..fc6a313ef80647c0181d9427749a42451d5d425a 100644 (file)
@@ -127,11 +127,7 @@ PRIVATE struct irq io_apic_irq[NR_IRQ_VECTORS];
  * to make APIC work if SMP is not configured, we need to set the maximal number
  * of CPUS to 1, cpuid to return 0 and the current cpu is always BSP
  */
-#ifndef CONFIG_SMP
-/* this is always true on an uniprocessor */
-#define cpu_is_bsp(x) 1
-
-#else
+#ifdef CONFIG_SMP
 
 #include "kernel/smp.h"
 
index b10abbaa9868ef3911e65e64af6e95d720ab250a..360786a33fe345914cb2aa44a2e7f2c5bee8b123 100644 (file)
@@ -190,15 +190,35 @@ PRIVATE void ap_finish_booting(void)
        while(!i386_paging_enabled)
                arch_pause();
 
+       /*
+        * Finish processor initialisation.  CPUs must be excluded from running.
+        * lapic timer calibration locks and unlocks the BKL because of the
+        * nested interrupts used for calibration. Therefore BKL is not good
+        * enough, the boot_lock must be held.
+        */
+       spinlock_lock(&boot_lock);
+       BKL_LOCK();
+
        /*
         * we must load some page tables befre we turn paging on. As VM is
         * always present we use those
         */
        segmentation2paging(proc_addr(VM_PROC_NR));
+       
+       printf("CPU %d paging is on\n", cpu);
+
+       lapic_enable(cpu);
+
+       if (app_cpu_init_timer(system_hz)) {
+               panic("FATAL : failed to initialize timer interrupts CPU %d, "
+                               "cannot continue without any clock source!", cpuid);
+       }
+       printf("CPU %d local APIC timer is ticking\n", cpu);
 
-       BKL_LOCK();
-       printf("CPU %d is running\n", cpu);
        BKL_UNLOCK();
+       
+       ap_boot_finished(cpu);
+       spinlock_unlock(&boot_lock);
        for(;;);
 
        /* finish processor initialisation. */
index 189d879ce832191371f6d671b48d198e88997159..0d923899989491ad592b95ade7d3c6d9386a47e7 100644 (file)
@@ -172,6 +172,9 @@ extern void * k_stacks;
 #define get_k_stack_top(cpu)   ((void *)(((char*)(k_stacks)) \
                                        + 2 * ((cpu) + 1) * K_STACK_SIZE))
 
+#define barrier()      do { mfence(); } while(0)
+
+
 #ifndef __GNUC__
 /* call a function to read the stack fram pointer (%ebp) */
 _PROTOTYPE(reg_t read_ebp, (void));
index 4687f782ae4bd692df91cac60d8661d347da5041..b0519631faca46d41a579e72b7af95a693f0a1bb 100644 (file)
@@ -999,6 +999,8 @@ ENTRY(arch_spinlock_unlock)
        mfence
        ret
 
+#endif /* CONFIG_SMP */
+
 /*===========================================================================*/
 /*                           mfence                                         */
 /*===========================================================================*/
@@ -1008,8 +1010,6 @@ ENTRY(mfence)
        mfence
        ret
 
-#endif /* CONFIG_SMP */
-
 /*===========================================================================*/
 /*                           arch_pause                                     */
 /*===========================================================================*/
index 10c432126215d98b28c2e33f3595a5d2dc3fa4a7..35fa5f6875cba631b5e5102e9ce85c91d752c3b6 100644 (file)
@@ -1083,12 +1083,15 @@ PUBLIC int arch_enable_paging(struct proc * caller, const message * m_ptr)
                        io_apic[i].addr = io_apic[i].vaddr;
                }
        }
-
-       /* TODO APs are still waiting, release them */
-#endif
+#if CONFIG_SMP
+       barrier();
 
        i386_paging_enabled = 1;
 
+       wait_for_APs_to_finish_booting();
+#endif
+#endif
+
 #ifdef CONFIG_WATCHDOG
        /*
         * We make sure that we don't enable the watchdog until paging is turned
index 6247f2c29e4c8ba3459ba610c646128487f172dc..ff80d1d4a2f39548f96ddf92fde6def78852b1f5 100644 (file)
@@ -61,6 +61,8 @@
 /* We only support 1 cpu now */
 #define CONFIG_MAX_CPUS        1
 #define cpuid          0
+/* this is always true on an uniprocessor */
+#define cpu_is_bsp(x) 1
 
 #else
 
index b0fafc2660e02b4bd1b7da3cb83c55ea2a66c5f3..367be59479c4ef11269cc6d295e35a354015761f 100644 (file)
@@ -6,4 +6,24 @@ unsigned bsp_cpu_id;
 
 struct cpu cpus[CONFIG_MAX_CPUS];
 
+static volatile unsigned ap_cpus_booted;
+
 SPINLOCK_DEFINE(big_kernel_lock)
+SPINLOCK_DEFINE(boot_lock)
+
+void wait_for_APs_to_finish_booting(void)
+{
+       /* we must let the other CPUs to run in kernel mode first */
+       BKL_UNLOCK();
+       while (ap_cpus_booted != (ncpus - 1))
+               arch_pause();
+       /* now we have to take the lock again as we continu execution */
+       BKL_LOCK();
+}
+
+void ap_boot_finished(unsigned cpu)
+{
+       printf("CPU %d is running\n", cpu);
+
+       ap_cpus_booted++;
+}
index 405db60e8f4be5d44219fc899e6c4207bdafd9dc..312dd144fdbeddfb5aca6e970f0ecf2d8705d22b 100644 (file)
@@ -49,7 +49,17 @@ EXTERN struct cpu cpus[CONFIG_MAX_CPUS];
 #define cpu_test_flag(cpu, flag) (cpus[cpu].flags & (flag))
 #define cpu_is_ready(cpu) cpu_test_flag(cpu, CPU_IS_READY)
 
+/*
+ * Big Kernel Lock prevents more then one cpu executing the kernel code
+ */
 SPINLOCK_DECLARE(big_kernel_lock)
+/*
+ * to sync the booting APs
+ */
+SPINLOCK_DECLARE(boot_lock)
+       
+_PROTOTYPE(void wait_for_APs_to_finish_booting, (void));
+_PROTOTYPE(void ap_boot_finished, (unsigned cpu));
 
 #endif /* __ASSEMBLY__ */