Clean CPU states in order to reuse smp boot code for CPU hotplug.
Signed-off-by: Li Shaohua<[email protected]>
---
linux-2.6.11-root/arch/i386/kernel/cpu/common.c | 12 ++++
linux-2.6.11-root/arch/i386/kernel/irq.c | 5 +
linux-2.6.11-root/arch/i386/kernel/process.c | 19 +++----
linux-2.6.11-root/arch/i386/kernel/smpboot.c | 62 ++++++++++++++++++++++--
linux-2.6.11-root/include/asm-i386/irq.h | 2
linux-2.6.11-root/include/asm-i386/smp.h | 5 +
6 files changed, 89 insertions(+), 16 deletions(-)
diff -puN arch/i386/kernel/cpu/common.c~cpu_state_clean arch/i386/kernel/cpu/common.c
--- linux-2.6.11/arch/i386/kernel/cpu/common.c~cpu_state_clean 2005-04-12 10:37:50.642376224 +0800
+++ linux-2.6.11-root/arch/i386/kernel/cpu/common.c 2005-04-12 10:37:50.654374400 +0800
@@ -644,3 +644,15 @@ void __devinit cpu_init (void)
clear_used_math();
mxcsr_feature_mask_init();
}
+
+#ifdef CONFIG_HOTPLUG_CPU
+void __devinit cpu_uninit(void)
+{
+ int cpu = _smp_processor_id();
+ cpu_clear(cpu, cpu_initialized);
+
+ /* lazy TLB state */
+ per_cpu(cpu_tlbstate, cpu).state = 0;
+ per_cpu(cpu_tlbstate, cpu).active_mm = &init_mm;
+}
+#endif
diff -puN arch/i386/kernel/irq.c~cpu_state_clean arch/i386/kernel/irq.c
--- linux-2.6.11/arch/i386/kernel/irq.c~cpu_state_clean 2005-04-12 10:37:50.643376072 +0800
+++ linux-2.6.11-root/arch/i386/kernel/irq.c 2005-04-12 10:37:50.654374400 +0800
@@ -158,6 +158,11 @@ void irq_ctx_init(int cpu)
cpu,hardirq_ctx[cpu],softirq_ctx[cpu]);
}
+void irq_ctx_exit(int cpu)
+{
+ hardirq_ctx[cpu] = NULL;
+}
+
extern asmlinkage void __do_softirq(void);
asmlinkage void do_softirq(void)
diff -puN arch/i386/kernel/process.c~cpu_state_clean arch/i386/kernel/process.c
--- linux-2.6.11/arch/i386/kernel/process.c~cpu_state_clean 2005-04-12 10:37:50.645375768 +0800
+++ linux-2.6.11-root/arch/i386/kernel/process.c 2005-04-12 10:37:50.655374248 +0800
@@ -148,21 +148,18 @@ static void poll_idle (void)
/* We don't actually take CPU down, just spin without interrupts. */
static inline void play_dead(void)
{
+ /* This must be done before dead CPU ack */
+ cpu_exit_clear();
+ mb();
/* Ack it */
__get_cpu_var(cpu_state) = CPU_DEAD;
- /* We shouldn't have to disable interrupts while dead, but
- * some interrupts just don't seem to go away, and this makes
- * it "work" for testing purposes. */
- /* Death loop */
- while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE)
- cpu_relax();
-
+ /*
+ * With physical CPU hotplug, we should halt the cpu
+ */
local_irq_disable();
- __flush_tlb_all();
- cpu_set(smp_processor_id(), cpu_online_map);
- enable_APIC_timer();
- local_irq_enable();
+ while (1)
+ __asm__ __volatile__("hlt":::"memory");
}
#else
static inline void play_dead(void)
diff -puN arch/i386/kernel/smpboot.c~cpu_state_clean arch/i386/kernel/smpboot.c
--- linux-2.6.11/arch/i386/kernel/smpboot.c~cpu_state_clean 2005-04-12 10:37:50.646375616 +0800
+++ linux-2.6.11-root/arch/i386/kernel/smpboot.c 2005-04-12 10:37:50.656374096 +0800
@@ -798,8 +798,18 @@ wakeup_secondary_cpu(int phys_apicid, un
#endif /* WAKE_SECONDARY_VIA_INIT */
extern cpumask_t cpu_initialized;
+static inline int alloc_cpu_id(void)
+{
+ cpumask_t tmp_map;
+ int cpu;
+ cpus_complement(tmp_map, cpu_present_map);
+ cpu = first_cpu(tmp_map);
+ if (cpu >= NR_CPUS)
+ return -ENODEV;
+ return cpu;
+}
-static int __devinit do_boot_cpu(int apicid)
+static int __devinit do_boot_cpu(int apicid, int cpu)
/*
* NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad
* (ie clustered apic addressing mode), this is a LOGICAL apic ID.
@@ -808,11 +818,12 @@ static int __devinit do_boot_cpu(int api
{
struct task_struct *idle;
unsigned long boot_error;
- int timeout, cpu;
+ int timeout;
unsigned long start_eip;
unsigned short nmi_high = 0, nmi_low = 0;
- cpu = ++cpucount;
+ ++cpucount;
+
/*
* We can't use kernel_thread since we must avoid to
* reschedule the child.
@@ -884,13 +895,16 @@ static int __devinit do_boot_cpu(int api
inquire_remote_apic(apicid);
}
}
- x86_cpu_to_apicid[cpu] = apicid;
+
if (boot_error) {
/* Try to put things back the way they were before ... */
unmap_cpu_to_logical_apicid(cpu);
cpu_clear(cpu, cpu_callout_map); /* was set here (do_boot_cpu()) */
cpu_clear(cpu, cpu_initialized); /* was set by cpu_init() */
cpucount--;
+ } else {
+ x86_cpu_to_apicid[cpu] = apicid;
+ cpu_set(cpu, cpu_present_map);
}
/* mark "stuck" area as not stuck */
@@ -899,6 +913,26 @@ static int __devinit do_boot_cpu(int api
return boot_error;
}
+#ifdef CONFIG_HOTPLUG_CPU
+void cpu_exit_clear(void)
+{
+ int cpu = _smp_processor_id();
+
+ idle_task_exit();
+
+ cpucount --;
+ cpu_uninit();
+ irq_ctx_exit(cpu);
+
+ cpu_clear(cpu, cpu_callout_map);
+ cpu_clear(cpu, cpu_callin_map);
+ cpu_clear(cpu, cpu_present_map);
+
+ cpu_clear(cpu, smp_commenced_mask);
+ unmap_cpu_to_logical_apicid(cpu);
+}
+#endif
+
static void smp_tune_scheduling (void)
{
unsigned long cachesize; /* kB */
@@ -1052,7 +1086,7 @@ static void __init smp_boot_cpus(unsigne
if (max_cpus <= cpucount+1)
continue;
- if (do_boot_cpu(apicid))
+ if ((cpu = alloc_cpu_id() > 0) && do_boot_cpu(apicid, cpu))
printk("CPU #%d not responding - cannot use it.\n",
apicid);
else
@@ -1131,6 +1165,7 @@ void __devinit smp_prepare_boot_cpu(void
{
cpu_set(smp_processor_id(), cpu_online_map);
cpu_set(smp_processor_id(), cpu_callout_map);
+ cpu_set(smp_processor_id(), cpu_present_map);
}
#ifdef CONFIG_HOTPLUG_CPU
@@ -1152,6 +1187,21 @@ static int __devinit cpu_enable(unsigned
return 0;
}
+static void
+remove_siblinginfo(int cpu)
+{
+ int sibling;
+
+ for_each_cpu_mask(sibling, cpu_sibling_map[cpu])
+ cpu_clear(cpu, cpu_sibling_map[sibling]);
+ for_each_cpu_mask(sibling, cpu_core_map[cpu])
+ cpu_clear(cpu, cpu_core_map[sibling]);
+ cpus_clear(cpu_sibling_map[cpu]);
+ cpus_clear(cpu_core_map[cpu]);
+ phys_proc_id[cpu] = BAD_APICID;
+ cpu_core_id[cpu] = BAD_APICID;
+}
+
int __cpu_disable(void)
{
cpumask_t map = cpu_online_map;
@@ -1175,6 +1225,8 @@ int __cpu_disable(void)
mdelay(1);
local_irq_disable();
+ remove_siblinginfo(cpu);
+
cpu_clear(cpu, map);
fixup_irqs(map);
/* It's now safe to remove this processor from the online map */
diff -puN include/asm-i386/irq.h~cpu_state_clean include/asm-i386/irq.h
--- linux-2.6.11/include/asm-i386/irq.h~cpu_state_clean 2005-04-12 10:37:50.648375312 +0800
+++ linux-2.6.11-root/include/asm-i386/irq.h 2005-04-12 10:37:50.656374096 +0800
@@ -29,9 +29,11 @@ extern void release_vm86_irqs(struct tas
#ifdef CONFIG_4KSTACKS
extern void irq_ctx_init(int cpu);
+ extern void irq_ctx_exit(int cpu);
# define __ARCH_HAS_DO_SOFTIRQ
#else
# define irq_ctx_init(cpu) do { } while (0)
+# define irq_ctx_exit(cpu) do { } while (0)
#endif
#ifdef CONFIG_IRQBALANCE
diff -puN include/asm-i386/smp.h~cpu_state_clean include/asm-i386/smp.h
--- linux-2.6.11/include/asm-i386/smp.h~cpu_state_clean 2005-04-12 10:37:50.649375160 +0800
+++ linux-2.6.11-root/include/asm-i386/smp.h 2005-04-12 10:37:50.656374096 +0800
@@ -49,6 +49,11 @@ extern void zap_low_mappings (void);
#define MAX_APICID 256
extern u8 x86_cpu_to_apicid[];
+#ifdef CONFIG_HOTPLUG_CPU
+extern void cpu_exit_clear(void);
+extern void cpu_uninit(void);
+#endif
+
/*
* This function is needed by all SMP systems. It must _always_ be valid
* from the initial startup. We map APIC_BASE very early in page_setup(),
_
-
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/
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Stuff]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
[Linux Resources]