|
@@ -536,15 +536,6 @@ do_boot_cpu(__u8 cpu)
|
|
|
& ~( voyager_extended_vic_processors
|
|
|
& voyager_allowed_boot_processors);
|
|
|
|
|
|
- /* For the 486, we can't use the 4Mb page table trick, so
|
|
|
- * must map a region of memory */
|
|
|
-#ifdef CONFIG_M486
|
|
|
- int i;
|
|
|
- unsigned long *page_table_copies = (unsigned long *)
|
|
|
- __get_free_page(GFP_KERNEL);
|
|
|
-#endif
|
|
|
- pgd_t orig_swapper_pg_dir0;
|
|
|
-
|
|
|
/* This is an area in head.S which was used to set up the
|
|
|
* initial kernel stack. We need to alter this to give the
|
|
|
* booting CPU a new stack (taken from its idle process) */
|
|
@@ -573,6 +564,8 @@ do_boot_cpu(__u8 cpu)
|
|
|
hijack_source.idt.Segment = (start_phys_address >> 4) & 0xFFFF;
|
|
|
|
|
|
cpucount++;
|
|
|
+ alternatives_smp_switch(1);
|
|
|
+
|
|
|
idle = fork_idle(cpu);
|
|
|
if(IS_ERR(idle))
|
|
|
panic("failed fork for CPU%d", cpu);
|
|
@@ -595,24 +588,11 @@ do_boot_cpu(__u8 cpu)
|
|
|
VDEBUG(("VOYAGER SMP: Booting CPU%d at 0x%lx[%x:%x], stack %p\n", cpu,
|
|
|
(unsigned long)hijack_source.val, hijack_source.idt.Segment,
|
|
|
hijack_source.idt.Offset, stack_start.esp));
|
|
|
- /* set the original swapper_pg_dir[0] to map 0 to 4Mb transparently
|
|
|
- * (so that the booting CPU can find start_32 */
|
|
|
- orig_swapper_pg_dir0 = swapper_pg_dir[0];
|
|
|
-#ifdef CONFIG_M486
|
|
|
- if(page_table_copies == NULL)
|
|
|
- panic("No free memory for 486 page tables\n");
|
|
|
- for(i = 0; i < PAGE_SIZE/sizeof(unsigned long); i++)
|
|
|
- page_table_copies[i] = (i * PAGE_SIZE)
|
|
|
- | _PAGE_RW | _PAGE_USER | _PAGE_PRESENT;
|
|
|
-
|
|
|
- ((unsigned long *)swapper_pg_dir)[0] =
|
|
|
- ((virt_to_phys(page_table_copies)) & PAGE_MASK)
|
|
|
- | _PAGE_RW | _PAGE_USER | _PAGE_PRESENT;
|
|
|
-#else
|
|
|
- ((unsigned long *)swapper_pg_dir)[0] =
|
|
|
- (virt_to_phys(pg0) & PAGE_MASK)
|
|
|
- | _PAGE_RW | _PAGE_USER | _PAGE_PRESENT;
|
|
|
-#endif
|
|
|
+
|
|
|
+ /* init lowmem identity mapping */
|
|
|
+ clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
|
|
|
+ min_t(unsigned long, KERNEL_PGD_PTRS, USER_PGD_PTRS));
|
|
|
+ flush_tlb_all();
|
|
|
|
|
|
if(quad_boot) {
|
|
|
printk("CPU %d: non extended Quad boot\n", cpu);
|
|
@@ -655,11 +635,7 @@ do_boot_cpu(__u8 cpu)
|
|
|
udelay(100);
|
|
|
}
|
|
|
/* reset the page table */
|
|
|
- swapper_pg_dir[0] = orig_swapper_pg_dir0;
|
|
|
- local_flush_tlb();
|
|
|
-#ifdef CONFIG_M486
|
|
|
- free_page((unsigned long)page_table_copies);
|
|
|
-#endif
|
|
|
+ zap_low_mappings();
|
|
|
|
|
|
if (cpu_booted_map) {
|
|
|
VDEBUG(("CPU%d: Booted successfully, back in CPU %d\n",
|
|
@@ -1082,20 +1058,11 @@ smp_call_function_interrupt(void)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/* Call this function on all CPUs using the function_interrupt above
|
|
|
- <func> The function to run. This must be fast and non-blocking.
|
|
|
- <info> An arbitrary pointer to pass to the function.
|
|
|
- <retry> If true, keep retrying until ready.
|
|
|
- <wait> If true, wait until function has completed on other CPUs.
|
|
|
- [RETURNS] 0 on success, else a negative status code. Does not return until
|
|
|
- remote CPUs are nearly ready to execute <<func>> or are or have executed.
|
|
|
-*/
|
|
|
-int
|
|
|
-smp_call_function (void (*func) (void *info), void *info, int retry,
|
|
|
- int wait)
|
|
|
+static int
|
|
|
+__smp_call_function_mask (void (*func) (void *info), void *info, int retry,
|
|
|
+ int wait, __u32 mask)
|
|
|
{
|
|
|
struct call_data_struct data;
|
|
|
- __u32 mask = cpus_addr(cpu_online_map)[0];
|
|
|
|
|
|
mask &= ~(1<<smp_processor_id());
|
|
|
|
|
@@ -1116,7 +1083,7 @@ smp_call_function (void (*func) (void *info), void *info, int retry,
|
|
|
call_data = &data;
|
|
|
wmb();
|
|
|
/* Send a message to all other CPUs and wait for them to respond */
|
|
|
- send_CPI_allbutself(VIC_CALL_FUNCTION_CPI);
|
|
|
+ send_CPI(mask, VIC_CALL_FUNCTION_CPI);
|
|
|
|
|
|
/* Wait for response */
|
|
|
while (data.started)
|
|
@@ -1130,8 +1097,48 @@ smp_call_function (void (*func) (void *info), void *info, int retry,
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
+
|
|
|
+/* Call this function on all CPUs using the function_interrupt above
|
|
|
+ <func> The function to run. This must be fast and non-blocking.
|
|
|
+ <info> An arbitrary pointer to pass to the function.
|
|
|
+ <retry> If true, keep retrying until ready.
|
|
|
+ <wait> If true, wait until function has completed on other CPUs.
|
|
|
+ [RETURNS] 0 on success, else a negative status code. Does not return until
|
|
|
+ remote CPUs are nearly ready to execute <<func>> or are or have executed.
|
|
|
+*/
|
|
|
+int
|
|
|
+smp_call_function(void (*func) (void *info), void *info, int retry,
|
|
|
+ int wait)
|
|
|
+{
|
|
|
+ __u32 mask = cpus_addr(cpu_online_map)[0];
|
|
|
+
|
|
|
+ return __smp_call_function_mask(func, info, retry, wait, mask);
|
|
|
+}
|
|
|
EXPORT_SYMBOL(smp_call_function);
|
|
|
|
|
|
+/*
|
|
|
+ * smp_call_function_single - Run a function on another CPU
|
|
|
+ * @func: The function to run. This must be fast and non-blocking.
|
|
|
+ * @info: An arbitrary pointer to pass to the function.
|
|
|
+ * @nonatomic: Currently unused.
|
|
|
+ * @wait: If true, wait until function has completed on other CPUs.
|
|
|
+ *
|
|
|
+ * Retrurns 0 on success, else a negative status code.
|
|
|
+ *
|
|
|
+ * Does not return until the remote CPU is nearly ready to execute <func>
|
|
|
+ * or is or has executed.
|
|
|
+ */
|
|
|
+
|
|
|
+int
|
|
|
+smp_call_function_single(int cpu, void (*func) (void *info), void *info,
|
|
|
+ int nonatomic, int wait)
|
|
|
+{
|
|
|
+ __u32 mask = 1 << cpu;
|
|
|
+
|
|
|
+ return __smp_call_function_mask(func, info, nonatomic, wait, mask);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(smp_call_function_single);
|
|
|
+
|
|
|
/* Sorry about the name. In an APIC based system, the APICs
|
|
|
* themselves are programmed to send a timer interrupt. This is used
|
|
|
* by linux to reschedule the processor. Voyager doesn't have this,
|