Re: [PATCH 5/6]physical CPU hot add

2005-04-12 Thread Li Shaohua
On Tue, 2005-04-12 at 20:17, Zwane Mwaikambo wrote:
> On Tue, 12 Apr 2005, Li Shaohua wrote:
> 
> >  #ifdef CONFIG_HOTPLUG_CPU
> > +int __attribute__ ((weak)) smp_prepare_cpu(int cpu)
> > +{
> > +   return 0;
> > +}
> > +
> 
> Any way for you to avoid using weak attribute?
Replace weak attribute with define method as suggested.

Thanks,
Shaohua


---

 linux-2.6.11-root/arch/i386/kernel/smpboot.c |  112 ---
 linux-2.6.11-root/drivers/base/cpu.c |7 +
 linux-2.6.11-root/include/asm-i386/smp.h |3 
 3 files changed, 93 insertions(+), 29 deletions(-)

diff -puN arch/i386/kernel/smpboot.c~warm_boot_cpu arch/i386/kernel/smpboot.c
--- linux-2.6.11/arch/i386/kernel/smpboot.c~warm_boot_cpu   2005-04-13 
10:58:37.152081456 +0800
+++ linux-2.6.11-root/arch/i386/kernel/smpboot.c2005-04-13 
10:58:37.159080392 +0800
@@ -80,6 +80,12 @@ cpumask_t cpu_callin_map;
 cpumask_t cpu_callout_map;
 static cpumask_t smp_commenced_mask;
 
+/* TSC's upper 32 bits can't be written in eariler CPU (before prescott), there
+ * is no way to resync one AP against BP. TBD: for prescott and above, we
+ * should use IA64's algorithm
+ */
+static int __devinitdata tsc_sync_disabled;
+
 /* Per CPU bogomips and other parameters */
 struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
 
@@ -416,7 +422,7 @@ static void __devinit smp_callin(void)
/*
 *  Synchronize the TSC with the BP
 */
-   if (cpu_has_tsc && cpu_khz)
+   if (cpu_has_tsc && cpu_khz && !tsc_sync_disabled)
synchronize_tsc_ap();
 }
 
@@ -809,6 +815,31 @@ static inline int alloc_cpu_id(void)
return cpu;
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static struct task_struct * __devinitdata cpu_idle_tasks[NR_CPUS];
+static inline struct task_struct * alloc_idle_task(int cpu)
+{
+   struct task_struct *idle;
+
+   if ((idle = cpu_idle_tasks[cpu]) != NULL) {
+   /* initialize thread_struct.  we really want to avoid destroy
+* idle tread
+*/
+   idle->thread.esp = (unsigned long)(((struct pt_regs *)
+   (THREAD_SIZE + (unsigned long) idle->thread_info)) - 1);
+   init_idle(idle, cpu);
+   return idle;
+   }
+   idle = fork_idle(cpu);
+
+   if (!IS_ERR(idle))
+   cpu_idle_tasks[cpu] = idle;
+   return idle;
+}
+#else
+#define alloc_idle_task(cpu) fork_idle(cpu)
+#endif
+
 static int __devinit do_boot_cpu(int apicid, int cpu)
 /*
  * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad
@@ -828,7 +859,7 @@ static int __devinit do_boot_cpu(int api
 * We can't use kernel_thread since we must avoid to
 * reschedule the child.
 */
-   idle = fork_idle(cpu);
+   idle = alloc_idle_task(cpu);
if (IS_ERR(idle))
panic("failed fork for CPU %d", cpu);
idle->thread.eip = (unsigned long) start_secondary;
@@ -931,6 +962,55 @@ void cpu_exit_clear(void)
cpu_clear(cpu, smp_commenced_mask);
unmap_cpu_to_logical_apicid(cpu);
 }
+
+struct warm_boot_cpu_info {
+   struct completion *complete;
+   int apicid;
+   int cpu;
+};
+
+static void __devinit do_warm_boot_cpu(void *p)
+{
+   struct warm_boot_cpu_info *info = p;
+   do_boot_cpu(info->apicid, info->cpu);
+   complete(info->complete);
+}
+
+int __devinit smp_prepare_cpu(int cpu)
+{
+   DECLARE_COMPLETION(done);
+   struct warm_boot_cpu_info info;
+   struct work_struct task;
+   int apicid, ret;
+
+   lock_cpu_hotplug();
+   apicid = x86_cpu_to_apicid[cpu];
+   if (apicid == BAD_APICID) {
+   ret = -ENODEV;
+   goto exit;
+   }
+
+   info.complete = 
+   info.apicid = apicid;
+   info.cpu = cpu;
+   INIT_WORK(, do_warm_boot_cpu, );
+
+   tsc_sync_disabled = 1;
+
+   /* init low mem mapping */
+   memcpy(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
+   sizeof(swapper_pg_dir[0]) * KERNEL_PGD_PTRS);
+   flush_tlb_all();
+   schedule_work();
+   wait_for_completion();
+
+   tsc_sync_disabled = 0;
+   zap_low_mappings();
+   ret = 0;
+exit:
+   unlock_cpu_hotplug();
+   return ret;
+}
 #endif
 
 static void smp_tune_scheduling (void)
@@ -1169,24 +1249,6 @@ void __devinit smp_prepare_boot_cpu(void
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
-
-/* must be called with the cpucontrol mutex held */
-static int __devinit cpu_enable(unsigned int cpu)
-{
-   /* get the target out of its holding state */
-   per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
-   wmb();
-
-   /* wait for the processor to ack it. timeout? */
-   while (!cpu_online(cpu))
-   cpu_relax();
-
-   fixup_irqs(cpu_online_map);
-   /* counter the disable in fixup_irqs() */
-   local_irq_enable();
-   return 0;
-}
-
 static void
 remove_siblinginfo(int cpu)
 {
@@ -1270,14 

Re: [PATCH 5/6]physical CPU hot add

2005-04-12 Thread Li Shaohua
On Tue, 2005-04-12 at 20:17, Zwane Mwaikambo wrote:
> On Tue, 12 Apr 2005, Li Shaohua wrote:
> 
> >  #ifdef CONFIG_HOTPLUG_CPU
> > +int __attribute__ ((weak)) smp_prepare_cpu(int cpu)
> > +{
> > +   return 0;
> > +}
> > +
> 
> Any way for you to avoid using weak attribute?
Just want to avoid more 'ifdef' or 'define empty routine for other
archs' staffs. Someone prefer 'weak' attribute. Either way is ok to me,
but if you think the former is better, I'd change it.

Thanks,
Shaohua

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 5/6]physical CPU hot add

2005-04-12 Thread Zwane Mwaikambo
On Tue, 12 Apr 2005, Li Shaohua wrote:

> On Tue, 2005-04-12 at 20:17, Zwane Mwaikambo wrote:
> > On Tue, 12 Apr 2005, Li Shaohua wrote:
> > 
> > >  #ifdef CONFIG_HOTPLUG_CPU
> > > +int __attribute__ ((weak)) smp_prepare_cpu(int cpu)
> > > +{
> > > + return 0;
> > > +}
> > > +
> > 
> > Any way for you to avoid using weak attribute?
> Just want to avoid more 'ifdef' or 'define empty routine for other
> archs' staffs. Someone prefer 'weak' attribute. Either way is ok to me,
> but if you think the former is better, I'd change it.

The define method is fine and preferred.

Thanks!
Zwane

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 5/6]physical CPU hot add

2005-04-12 Thread Zwane Mwaikambo
On Tue, 12 Apr 2005, Li Shaohua wrote:

>  #ifdef CONFIG_HOTPLUG_CPU
> +int __attribute__ ((weak)) smp_prepare_cpu(int cpu)
> +{
> + return 0;
> +}
> +

Any way for you to avoid using weak attribute?

Thanks,
Zwane
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 5/6]physical CPU hot add

2005-04-12 Thread Zwane Mwaikambo
On Tue, 12 Apr 2005, Li Shaohua wrote:

  #ifdef CONFIG_HOTPLUG_CPU
 +int __attribute__ ((weak)) smp_prepare_cpu(int cpu)
 +{
 + return 0;
 +}
 +

Any way for you to avoid using weak attribute?

Thanks,
Zwane
-
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 5/6]physical CPU hot add

2005-04-12 Thread Zwane Mwaikambo
On Tue, 12 Apr 2005, Li Shaohua wrote:

 On Tue, 2005-04-12 at 20:17, Zwane Mwaikambo wrote:
  On Tue, 12 Apr 2005, Li Shaohua wrote:
  
#ifdef CONFIG_HOTPLUG_CPU
   +int __attribute__ ((weak)) smp_prepare_cpu(int cpu)
   +{
   + return 0;
   +}
   +
  
  Any way for you to avoid using weak attribute?
 Just want to avoid more 'ifdef' or 'define empty routine for other
 archs' staffs. Someone prefer 'weak' attribute. Either way is ok to me,
 but if you think the former is better, I'd change it.

The define method is fine and preferred.

Thanks!
Zwane

-
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 5/6]physical CPU hot add

2005-04-12 Thread Li Shaohua
On Tue, 2005-04-12 at 20:17, Zwane Mwaikambo wrote:
 On Tue, 12 Apr 2005, Li Shaohua wrote:
 
   #ifdef CONFIG_HOTPLUG_CPU
  +int __attribute__ ((weak)) smp_prepare_cpu(int cpu)
  +{
  +   return 0;
  +}
  +
 
 Any way for you to avoid using weak attribute?
Just want to avoid more 'ifdef' or 'define empty routine for other
archs' staffs. Someone prefer 'weak' attribute. Either way is ok to me,
but if you think the former is better, I'd change it.

Thanks,
Shaohua

-
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 5/6]physical CPU hot add

2005-04-12 Thread Li Shaohua
On Tue, 2005-04-12 at 20:17, Zwane Mwaikambo wrote:
 On Tue, 12 Apr 2005, Li Shaohua wrote:
 
   #ifdef CONFIG_HOTPLUG_CPU
  +int __attribute__ ((weak)) smp_prepare_cpu(int cpu)
  +{
  +   return 0;
  +}
  +
 
 Any way for you to avoid using weak attribute?
Replace weak attribute with define method as suggested.

Thanks,
Shaohua


---

 linux-2.6.11-root/arch/i386/kernel/smpboot.c |  112 ---
 linux-2.6.11-root/drivers/base/cpu.c |7 +
 linux-2.6.11-root/include/asm-i386/smp.h |3 
 3 files changed, 93 insertions(+), 29 deletions(-)

diff -puN arch/i386/kernel/smpboot.c~warm_boot_cpu arch/i386/kernel/smpboot.c
--- linux-2.6.11/arch/i386/kernel/smpboot.c~warm_boot_cpu   2005-04-13 
10:58:37.152081456 +0800
+++ linux-2.6.11-root/arch/i386/kernel/smpboot.c2005-04-13 
10:58:37.159080392 +0800
@@ -80,6 +80,12 @@ cpumask_t cpu_callin_map;
 cpumask_t cpu_callout_map;
 static cpumask_t smp_commenced_mask;
 
+/* TSC's upper 32 bits can't be written in eariler CPU (before prescott), there
+ * is no way to resync one AP against BP. TBD: for prescott and above, we
+ * should use IA64's algorithm
+ */
+static int __devinitdata tsc_sync_disabled;
+
 /* Per CPU bogomips and other parameters */
 struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
 
@@ -416,7 +422,7 @@ static void __devinit smp_callin(void)
/*
 *  Synchronize the TSC with the BP
 */
-   if (cpu_has_tsc  cpu_khz)
+   if (cpu_has_tsc  cpu_khz  !tsc_sync_disabled)
synchronize_tsc_ap();
 }
 
@@ -809,6 +815,31 @@ static inline int alloc_cpu_id(void)
return cpu;
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static struct task_struct * __devinitdata cpu_idle_tasks[NR_CPUS];
+static inline struct task_struct * alloc_idle_task(int cpu)
+{
+   struct task_struct *idle;
+
+   if ((idle = cpu_idle_tasks[cpu]) != NULL) {
+   /* initialize thread_struct.  we really want to avoid destroy
+* idle tread
+*/
+   idle-thread.esp = (unsigned long)(((struct pt_regs *)
+   (THREAD_SIZE + (unsigned long) idle-thread_info)) - 1);
+   init_idle(idle, cpu);
+   return idle;
+   }
+   idle = fork_idle(cpu);
+
+   if (!IS_ERR(idle))
+   cpu_idle_tasks[cpu] = idle;
+   return idle;
+}
+#else
+#define alloc_idle_task(cpu) fork_idle(cpu)
+#endif
+
 static int __devinit do_boot_cpu(int apicid, int cpu)
 /*
  * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad
@@ -828,7 +859,7 @@ static int __devinit do_boot_cpu(int api
 * We can't use kernel_thread since we must avoid to
 * reschedule the child.
 */
-   idle = fork_idle(cpu);
+   idle = alloc_idle_task(cpu);
if (IS_ERR(idle))
panic(failed fork for CPU %d, cpu);
idle-thread.eip = (unsigned long) start_secondary;
@@ -931,6 +962,55 @@ void cpu_exit_clear(void)
cpu_clear(cpu, smp_commenced_mask);
unmap_cpu_to_logical_apicid(cpu);
 }
+
+struct warm_boot_cpu_info {
+   struct completion *complete;
+   int apicid;
+   int cpu;
+};
+
+static void __devinit do_warm_boot_cpu(void *p)
+{
+   struct warm_boot_cpu_info *info = p;
+   do_boot_cpu(info-apicid, info-cpu);
+   complete(info-complete);
+}
+
+int __devinit smp_prepare_cpu(int cpu)
+{
+   DECLARE_COMPLETION(done);
+   struct warm_boot_cpu_info info;
+   struct work_struct task;
+   int apicid, ret;
+
+   lock_cpu_hotplug();
+   apicid = x86_cpu_to_apicid[cpu];
+   if (apicid == BAD_APICID) {
+   ret = -ENODEV;
+   goto exit;
+   }
+
+   info.complete = done;
+   info.apicid = apicid;
+   info.cpu = cpu;
+   INIT_WORK(task, do_warm_boot_cpu, info);
+
+   tsc_sync_disabled = 1;
+
+   /* init low mem mapping */
+   memcpy(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
+   sizeof(swapper_pg_dir[0]) * KERNEL_PGD_PTRS);
+   flush_tlb_all();
+   schedule_work(task);
+   wait_for_completion(done);
+
+   tsc_sync_disabled = 0;
+   zap_low_mappings();
+   ret = 0;
+exit:
+   unlock_cpu_hotplug();
+   return ret;
+}
 #endif
 
 static void smp_tune_scheduling (void)
@@ -1169,24 +1249,6 @@ void __devinit smp_prepare_boot_cpu(void
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
-
-/* must be called with the cpucontrol mutex held */
-static int __devinit cpu_enable(unsigned int cpu)
-{
-   /* get the target out of its holding state */
-   per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
-   wmb();
-
-   /* wait for the processor to ack it. timeout? */
-   while (!cpu_online(cpu))
-   cpu_relax();
-
-   fixup_irqs(cpu_online_map);
-   /* counter the disable in fixup_irqs() */
-   local_irq_enable();
-   return 0;
-}
-
 static void
 remove_siblinginfo(int cpu)
 {
@@ -1270,14 +1332,6 @@ 

[PATCH 5/6]physical CPU hot add

2005-04-11 Thread Li Shaohua
Boot a CPU at runtime.

Signed-off-by: Li Shaohua<[EMAIL PROTECTED]>
---

 linux-2.6.11-root/arch/i386/kernel/smpboot.c |  112 ---
 linux-2.6.11-root/drivers/base/cpu.c |8 +
 linux-2.6.11-root/include/asm-i386/smp.h |2 
 3 files changed, 93 insertions(+), 29 deletions(-)

diff -puN arch/i386/kernel/smpboot.c~warm_boot_cpu arch/i386/kernel/smpboot.c
--- linux-2.6.11/arch/i386/kernel/smpboot.c~warm_boot_cpu   2005-04-12 
10:38:16.720411760 +0800
+++ linux-2.6.11-root/arch/i386/kernel/smpboot.c2005-04-12 
11:11:09.16040 +0800
@@ -80,6 +80,12 @@ cpumask_t cpu_callin_map;
 cpumask_t cpu_callout_map;
 static cpumask_t smp_commenced_mask;
 
+/* TSC's upper 32 bits can't be written in eariler CPU (before prescott), there
+ * is no way to resync one AP against BP. TBD: for prescott and above, we
+ * should use IA64's algorithm
+ */
+static int __devinitdata tsc_sync_disabled;
+
 /* Per CPU bogomips and other parameters */
 struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
 
@@ -416,7 +422,7 @@ static void __devinit smp_callin(void)
/*
 *  Synchronize the TSC with the BP
 */
-   if (cpu_has_tsc && cpu_khz)
+   if (cpu_has_tsc && cpu_khz && !tsc_sync_disabled)
synchronize_tsc_ap();
 }
 
@@ -809,6 +815,31 @@ static inline int alloc_cpu_id(void)
return cpu;
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static struct task_struct * __devinitdata cpu_idle_tasks[NR_CPUS];
+static inline struct task_struct * alloc_idle_task(int cpu)
+{
+   struct task_struct *idle;
+
+   if ((idle = cpu_idle_tasks[cpu]) != NULL) {
+   /* initialize thread_struct.  we really want to avoid destroy
+* idle tread
+*/
+   idle->thread.esp = (unsigned long)(((struct pt_regs *)
+   (THREAD_SIZE + (unsigned long) idle->thread_info)) - 1);
+   init_idle(idle, cpu);
+   return idle;
+   }
+   idle = fork_idle(cpu);
+
+   if (!IS_ERR(idle))
+   cpu_idle_tasks[cpu] = idle;
+   return idle;
+}
+#else
+#define alloc_idle_task(cpu) fork_idle(cpu)
+#endif
+
 static int __devinit do_boot_cpu(int apicid, int cpu)
 /*
  * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad
@@ -828,7 +859,7 @@ static int __devinit do_boot_cpu(int api
 * We can't use kernel_thread since we must avoid to
 * reschedule the child.
 */
-   idle = fork_idle(cpu);
+   idle = alloc_idle_task(cpu);
if (IS_ERR(idle))
panic("failed fork for CPU %d", cpu);
idle->thread.eip = (unsigned long) start_secondary;
@@ -931,6 +962,55 @@ void cpu_exit_clear(void)
cpu_clear(cpu, smp_commenced_mask);
unmap_cpu_to_logical_apicid(cpu);
 }
+
+struct warm_boot_cpu_info {
+   struct completion *complete;
+   int apicid;
+   int cpu;
+};
+
+static void __devinit do_warm_boot_cpu(void *p)
+{
+   struct warm_boot_cpu_info *info = p;
+   do_boot_cpu(info->apicid, info->cpu);
+   complete(info->complete);
+}
+
+int __devinit smp_prepare_cpu(int cpu)
+{
+   DECLARE_COMPLETION(done);
+   struct warm_boot_cpu_info info;
+   struct work_struct task;
+   int apicid, ret;
+
+   lock_cpu_hotplug();
+   apicid = x86_cpu_to_apicid[cpu];
+   if (apicid == BAD_APICID) {
+   ret = -ENODEV;
+   goto exit;
+   }
+
+   info.complete = 
+   info.apicid = apicid;
+   info.cpu = cpu;
+   INIT_WORK(, do_warm_boot_cpu, );
+
+   tsc_sync_disabled = 1;
+
+   /* init low mem mapping */
+   memcpy(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
+   sizeof(swapper_pg_dir[0]) * KERNEL_PGD_PTRS);
+   flush_tlb_all();
+   schedule_work();
+   wait_for_completion();
+
+   tsc_sync_disabled = 0;
+   zap_low_mappings();
+   ret = 0;
+exit:
+   unlock_cpu_hotplug();
+   return ret;
+}
 #endif
 
 static void smp_tune_scheduling (void)
@@ -1169,24 +1249,6 @@ void __devinit smp_prepare_boot_cpu(void
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
-
-/* must be called with the cpucontrol mutex held */
-static int __devinit cpu_enable(unsigned int cpu)
-{
-   /* get the target out of its holding state */
-   per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
-   wmb();
-
-   /* wait for the processor to ack it. timeout? */
-   while (!cpu_online(cpu))
-   cpu_relax();
-
-   fixup_irqs(cpu_online_map);
-   /* counter the disable in fixup_irqs() */
-   local_irq_enable();
-   return 0;
-}
-
 static void
 remove_siblinginfo(int cpu)
 {
@@ -1270,14 +1332,6 @@ int __devinit __cpu_up(unsigned int cpu)
return -EIO;
}
 
-#ifdef CONFIG_HOTPLUG_CPU
-   /* Already up, and in cpu_quiescent now? */
-   if (cpu_isset(cpu, smp_commenced_mask)) {
-   cpu_enable(cpu);
-   return 0;
- 

[PATCH 5/6]physical CPU hot add

2005-04-11 Thread Li Shaohua
Boot a CPU at runtime.

Signed-off-by: Li Shaohua[EMAIL PROTECTED]
---

 linux-2.6.11-root/arch/i386/kernel/smpboot.c |  112 ---
 linux-2.6.11-root/drivers/base/cpu.c |8 +
 linux-2.6.11-root/include/asm-i386/smp.h |2 
 3 files changed, 93 insertions(+), 29 deletions(-)

diff -puN arch/i386/kernel/smpboot.c~warm_boot_cpu arch/i386/kernel/smpboot.c
--- linux-2.6.11/arch/i386/kernel/smpboot.c~warm_boot_cpu   2005-04-12 
10:38:16.720411760 +0800
+++ linux-2.6.11-root/arch/i386/kernel/smpboot.c2005-04-12 
11:11:09.16040 +0800
@@ -80,6 +80,12 @@ cpumask_t cpu_callin_map;
 cpumask_t cpu_callout_map;
 static cpumask_t smp_commenced_mask;
 
+/* TSC's upper 32 bits can't be written in eariler CPU (before prescott), there
+ * is no way to resync one AP against BP. TBD: for prescott and above, we
+ * should use IA64's algorithm
+ */
+static int __devinitdata tsc_sync_disabled;
+
 /* Per CPU bogomips and other parameters */
 struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
 
@@ -416,7 +422,7 @@ static void __devinit smp_callin(void)
/*
 *  Synchronize the TSC with the BP
 */
-   if (cpu_has_tsc  cpu_khz)
+   if (cpu_has_tsc  cpu_khz  !tsc_sync_disabled)
synchronize_tsc_ap();
 }
 
@@ -809,6 +815,31 @@ static inline int alloc_cpu_id(void)
return cpu;
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static struct task_struct * __devinitdata cpu_idle_tasks[NR_CPUS];
+static inline struct task_struct * alloc_idle_task(int cpu)
+{
+   struct task_struct *idle;
+
+   if ((idle = cpu_idle_tasks[cpu]) != NULL) {
+   /* initialize thread_struct.  we really want to avoid destroy
+* idle tread
+*/
+   idle-thread.esp = (unsigned long)(((struct pt_regs *)
+   (THREAD_SIZE + (unsigned long) idle-thread_info)) - 1);
+   init_idle(idle, cpu);
+   return idle;
+   }
+   idle = fork_idle(cpu);
+
+   if (!IS_ERR(idle))
+   cpu_idle_tasks[cpu] = idle;
+   return idle;
+}
+#else
+#define alloc_idle_task(cpu) fork_idle(cpu)
+#endif
+
 static int __devinit do_boot_cpu(int apicid, int cpu)
 /*
  * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad
@@ -828,7 +859,7 @@ static int __devinit do_boot_cpu(int api
 * We can't use kernel_thread since we must avoid to
 * reschedule the child.
 */
-   idle = fork_idle(cpu);
+   idle = alloc_idle_task(cpu);
if (IS_ERR(idle))
panic(failed fork for CPU %d, cpu);
idle-thread.eip = (unsigned long) start_secondary;
@@ -931,6 +962,55 @@ void cpu_exit_clear(void)
cpu_clear(cpu, smp_commenced_mask);
unmap_cpu_to_logical_apicid(cpu);
 }
+
+struct warm_boot_cpu_info {
+   struct completion *complete;
+   int apicid;
+   int cpu;
+};
+
+static void __devinit do_warm_boot_cpu(void *p)
+{
+   struct warm_boot_cpu_info *info = p;
+   do_boot_cpu(info-apicid, info-cpu);
+   complete(info-complete);
+}
+
+int __devinit smp_prepare_cpu(int cpu)
+{
+   DECLARE_COMPLETION(done);
+   struct warm_boot_cpu_info info;
+   struct work_struct task;
+   int apicid, ret;
+
+   lock_cpu_hotplug();
+   apicid = x86_cpu_to_apicid[cpu];
+   if (apicid == BAD_APICID) {
+   ret = -ENODEV;
+   goto exit;
+   }
+
+   info.complete = done;
+   info.apicid = apicid;
+   info.cpu = cpu;
+   INIT_WORK(task, do_warm_boot_cpu, info);
+
+   tsc_sync_disabled = 1;
+
+   /* init low mem mapping */
+   memcpy(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
+   sizeof(swapper_pg_dir[0]) * KERNEL_PGD_PTRS);
+   flush_tlb_all();
+   schedule_work(task);
+   wait_for_completion(done);
+
+   tsc_sync_disabled = 0;
+   zap_low_mappings();
+   ret = 0;
+exit:
+   unlock_cpu_hotplug();
+   return ret;
+}
 #endif
 
 static void smp_tune_scheduling (void)
@@ -1169,24 +1249,6 @@ void __devinit smp_prepare_boot_cpu(void
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
-
-/* must be called with the cpucontrol mutex held */
-static int __devinit cpu_enable(unsigned int cpu)
-{
-   /* get the target out of its holding state */
-   per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
-   wmb();
-
-   /* wait for the processor to ack it. timeout? */
-   while (!cpu_online(cpu))
-   cpu_relax();
-
-   fixup_irqs(cpu_online_map);
-   /* counter the disable in fixup_irqs() */
-   local_irq_enable();
-   return 0;
-}
-
 static void
 remove_siblinginfo(int cpu)
 {
@@ -1270,14 +1332,6 @@ int __devinit __cpu_up(unsigned int cpu)
return -EIO;
}
 
-#ifdef CONFIG_HOTPLUG_CPU
-   /* Already up, and in cpu_quiescent now? */
-   if (cpu_isset(cpu, smp_commenced_mask)) {
-   cpu_enable(cpu);
-   return