summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Braun <rbraun@sceen.net>2012-12-12 23:04:26 +0100
committerRichard Braun <rbraun@sceen.net>2012-12-12 23:04:26 +0100
commit45acb625b17ca642fa968a7ca41e0a03e8e9ccfb (patch)
tree944e86a982b2576b10dcacffb1e9439823c09bb6
parent51bff7b18de9329d7bd77324cc597e72173fae74 (diff)
Simplify requirements on interrupts during initialization
Don't involve the pmap module directly, as there could be others. Make the cpu module completely responsible for synchronizing all processors on kernel entry so that interrupts can be explicitely enabled there.
-rw-r--r--arch/x86/machine/cpu.c30
-rw-r--r--arch/x86/machine/cpu.h15
-rw-r--r--arch/x86/machine/pmap.c23
-rw-r--r--arch/x86/machine/pmap.h7
-rw-r--r--kern/kernel.c7
-rw-r--r--kern/kernel.h4
6 files changed, 42 insertions, 44 deletions
diff --git a/arch/x86/machine/cpu.c b/arch/x86/machine/cpu.c
index 82af7c30..b0567943 100644
--- a/arch/x86/machine/cpu.c
+++ b/arch/x86/machine/cpu.c
@@ -70,7 +70,12 @@ struct cpu cpu_array[MAX_CPUS];
/*
* Number of configured processors.
+ *
+ * The boot version is used until all processors are configured, since some
+ * modules depend on cpu_count() to adjust their behaviour when several
+ * processors are present.
*/
+static unsigned int cpu_boot_array_size;
unsigned int cpu_array_size;
/*
@@ -298,6 +303,7 @@ cpu_setup(void)
cpu_array[i].state = CPU_STATE_OFF;
}
+ cpu_boot_array_size = 1;
cpu_array_size = 1;
cpu_init(&cpu_array[0]);
}
@@ -341,13 +347,13 @@ cpu_mp_register_lapic(unsigned int apic_id, int is_bsp)
return;
}
- if (cpu_array_size == ARRAY_SIZE(cpu_array)) {
+ if (cpu_boot_array_size == ARRAY_SIZE(cpu_array)) {
printk("cpu: ignoring processor beyond id %u\n", MAX_CPUS - 1);
return;
}
- cpu_array[cpu_array_size].apic_id = apic_id;
- cpu_array_size++;
+ cpu_array[cpu_boot_array_size].apic_id = apic_id;
+ cpu_boot_array_size++;
}
static void __init
@@ -360,7 +366,7 @@ cpu_mp_start_aps(void)
size_t map_size;
unsigned int i;
- if (cpu_array_size == 1)
+ if (cpu_boot_array_size == 1)
return;
assert(BOOT_MP_TRAMPOLINE_ADDR < BIOSMEM_BASE);
@@ -396,7 +402,7 @@ cpu_mp_start_aps(void)
* Preallocate stacks now, as the kernel mappings shouldn't change while
* the APs are bootstrapping.
*/
- for (i = 1; i < cpu_array_size; i++) {
+ for (i = 1; i < cpu_boot_array_size; i++) {
cpu = &cpu_array[i];
cpu->boot_stack = vm_kmem_alloc(BOOT_STACK_SIZE);
@@ -405,7 +411,7 @@ cpu_mp_start_aps(void)
}
/* Perform the "Universal Start-up Algorithm" */
- for (i = 1; i < cpu_array_size; i++) {
+ for (i = 1; i < cpu_boot_array_size; i++) {
cpu = &cpu_array[i];
boot_ap_id = i;
@@ -424,6 +430,8 @@ cpu_mp_start_aps(void)
while (cpu->state == CPU_STATE_OFF)
cpu_pause();
}
+
+ cpu_array_size = cpu_boot_array_size;
}
static void __init
@@ -437,8 +445,6 @@ cpu_mp_setup(void)
{
acpimp_setup();
cpu_mp_start_aps();
- cpu_intr_enable();
- pmap_mp_setup();
cpu_mp_info();
}
@@ -448,5 +454,11 @@ cpu_ap_setup(void)
cpu_init(&cpu_array[boot_ap_id]);
cpu_check(cpu_current());
lapic_ap_setup();
- cpu_intr_enable();
+}
+
+void __init
+cpu_ap_sync(void)
+{
+ while (cpu_count() == 1)
+ cpu_pause();
}
diff --git a/arch/x86/machine/cpu.h b/arch/x86/machine/cpu.h
index 674892ad..66376e3a 100644
--- a/arch/x86/machine/cpu.h
+++ b/arch/x86/machine/cpu.h
@@ -436,18 +436,25 @@ void cpu_mp_register_lapic(unsigned int apic_id, int is_bsp);
/*
* Probe application processors and start them.
- *
- * This function enables interrupts.
*/
void cpu_mp_setup(void);
/*
* CPU initialization on APs.
- *
- * This function enables interrupts.
*/
void cpu_ap_setup(void);
+/*
+ * Synchronize processors on kernel entry.
+ *
+ * Wait for all processors to reach a proper state when entering the kernel,
+ * so that memory allocations can proceed and thread scheduling started.
+ *
+ * Once this function returns, cpu_count can be used reliably to know if there
+ * are more than one processors, and how many.
+ */
+void cpu_ap_sync(void);
+
#endif /* __ASSEMBLER__ */
#endif /* _X86_CPU_H */
diff --git a/arch/x86/machine/pmap.c b/arch/x86/machine/pmap.c
index cbd08b59..65f9708a 100644
--- a/arch/x86/machine/pmap.c
+++ b/arch/x86/machine/pmap.c
@@ -148,11 +148,6 @@ static unsigned long pmap_zero_va;
static struct spinlock pmap_zero_va_lock;
/*
- * True if running on multiple processors (TLB flushes must be propagated).
- */
-static volatile int pmap_mp_mode;
-
-/*
* Shared variables used by the inter-processor update functions.
*/
static unsigned long pmap_update_start;
@@ -364,6 +359,7 @@ pmap_bootstrap(void)
cpu_tlb_flush();
+ spinlock_init(&pmap_update_lock);
pmap_kernel_limit = VM_MIN_KERNEL_ADDRESS;
}
@@ -372,9 +368,6 @@ pmap_ap_bootstrap(void)
{
if (cpu_has_global_pages())
cpu_enable_global_pages();
-
- while (!pmap_mp_mode)
- cpu_pause();
}
unsigned long __init
@@ -507,10 +500,7 @@ pmap_kupdate(unsigned long start, unsigned long end)
{
unsigned int nr_cpus;
- if (pmap_mp_mode)
- nr_cpus = cpu_count();
- else
- nr_cpus = 1;
+ nr_cpus = cpu_count();
if (nr_cpus == 1) {
pmap_kupdate_local(start, end);
@@ -556,15 +546,6 @@ pmap_kextract(unsigned long va)
}
void
-pmap_mp_setup(void)
-{
- assert(cpu_intr_enabled());
-
- spinlock_init(&pmap_update_lock);
- pmap_mp_mode = 1;
-}
-
-void
pmap_update_intr(struct trap_frame *frame)
{
(void)frame;
diff --git a/arch/x86/machine/pmap.h b/arch/x86/machine/pmap.h
index 89b36b52..018bf900 100644
--- a/arch/x86/machine/pmap.h
+++ b/arch/x86/machine/pmap.h
@@ -176,13 +176,6 @@ void pmap_kupdate(unsigned long start, unsigned long end);
phys_addr_t pmap_kextract(unsigned long va);
/*
- * Prepare the pmap module for a multiprocessor environment.
- *
- * Interrupts must be enabled when calling this function.
- */
-void pmap_mp_setup(void);
-
-/*
* Interrupt handler for inter-processor update requests.
*/
void pmap_update_intr(struct trap_frame *frame);
diff --git a/kern/kernel.c b/kern/kernel.c
index 760f68e8..07a0f660 100644
--- a/kern/kernel.c
+++ b/kern/kernel.c
@@ -30,7 +30,7 @@ kernel_main(void)
task_setup();
thread_setup();
- /* Interrupts are enabled by this call */
+ cpu_intr_enable();
cpu_mp_setup();
thread_run();
@@ -41,7 +41,10 @@ kernel_main(void)
void __init
kernel_ap_main(void)
{
- assert(cpu_intr_enabled());
+ assert(!cpu_intr_enabled());
+
+ cpu_intr_enable();
+ cpu_ap_sync();
thread_run();
diff --git a/kern/kernel.h b/kern/kernel.h
index 22d5714b..f5821ca6 100644
--- a/kern/kernel.h
+++ b/kern/kernel.h
@@ -26,13 +26,15 @@
/*
* Machine-independent entry point.
+ *
+ * Interrupts must be disabled when calling this function.
*/
void kernel_main(void);
/*
* Entry point for APs.
*
- * Interrupts must be enabled when calling this function.
+ * Interrupts must be disabled when calling this function.
*/
void kernel_ap_main(void);