[PATCH][2.5][2/5] CPU Hotplug i386 core

From: Zwane Mwaikambo (zwane@holomorphy.com)
Date: Mon Feb 17 2003 - 03:14:08 EST


 arch/i386/kernel/irq.c | 18 ++++++++++++
 arch/i386/kernel/process.c | 39 ++++++++++++++++++++++++++-
 arch/i386/kernel/smp.c | 18 ++++++++++--
 arch/i386/kernel/smpboot.c | 63 ++++++++++++++++++++++++++++++++++++++++++---
 include/asm-i386/smp.h | 4 ++
 5 files changed, 133 insertions(+), 9 deletions(-)

Index: linux-2.5.61-trojan/include/asm-i386/smp.h
===================================================================
RCS file: /build/cvsroot/linux-2.5.61/include/asm-i386/smp.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 smp.h
--- linux-2.5.61-trojan/include/asm-i386/smp.h 15 Feb 2003 12:32:04 -0000 1.1.1.1
+++ linux-2.5.61-trojan/include/asm-i386/smp.h 15 Feb 2003 19:31:05 -0000
@@ -100,6 +100,10 @@
 }
 
 #endif
+
+extern int __cpu_disable(void);
+extern void __cpu_die(unsigned int cpu);
+
 #endif /* !__ASSEMBLY__ */
 
 #define NO_PROC_ID 0xFF /* No processor magic marker */
Index: linux-2.5.61-trojan/arch/i386/kernel/irq.c
===================================================================
RCS file: /build/cvsroot/linux-2.5.61/arch/i386/kernel/irq.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 irq.c
--- linux-2.5.61-trojan/arch/i386/kernel/irq.c 15 Feb 2003 12:32:09 -0000 1.1.1.1
+++ linux-2.5.61-trojan/arch/i386/kernel/irq.c 15 Feb 2003 21:23:09 -0000
@@ -870,6 +870,24 @@
         return full_count;
 }
 
+void migrate_irqs_from(unsigned int cpu)
+{
+ unsigned long mask = cpu_online_map & ~(1UL << cpu);
+ unsigned int irq;
+
+ for (irq = 0; irq < NR_IRQS; irq++) {
+ if (!irq_desc[irq].handler->set_affinity)
+ continue;
+
+ irq_affinity[irq] &= mask;
+ if (irq_affinity[irq] == 0) {
+ irq_affinity[irq] = mask;
+ printk(KERN_INFO "dying cpu%d has irq%d affined to it, setting to %lx\n",
+ cpu, irq, mask);
+ }
+ irq_desc[irq].handler->set_affinity(irq, mask);
+ }
+}
 #endif
 
 static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
Index: linux-2.5.61-trojan/arch/i386/kernel/process.c
===================================================================
RCS file: /build/cvsroot/linux-2.5.61/arch/i386/kernel/process.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 process.c
--- linux-2.5.61-trojan/arch/i386/kernel/process.c 15 Feb 2003 12:32:09 -0000 1.1.1.1
+++ linux-2.5.61-trojan/arch/i386/kernel/process.c 17 Feb 2003 06:47:05 -0000
@@ -36,7 +36,7 @@
 #include <linux/mc146818rtc.h>
 #include <linux/module.h>
 #include <linux/kallsyms.h>
-
+#include <linux/brlock.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -46,6 +46,7 @@
 #include <asm/i387.h>
 #include <asm/irq.h>
 #include <asm/desc.h>
+#include <asm/tlbflush.h>
 #ifdef CONFIG_MATH_EMULATION
 #include <asm/math_emu.h>
 #endif
@@ -80,6 +81,8 @@
         hlt_counter--;
 }
 
+DECLARE_PER_CPU(int, cpu_die);
+
 /*
  * We use this if we don't have any better
  * idle routine..
@@ -127,6 +130,36 @@
         }
 }
 
+#if defined(CONFIG_HOTPLUG) && defined(CONFIG_SMP)
+static inline void maybe_play_dead(void)
+{
+ if (unlikely(__get_cpu_var(cpu_die))) {
+ printk("Cpu %u Dust Dust Dust\n", smp_processor_id());
+ /* Ack it */
+ __get_cpu_var(cpu_die) = 2;
+
+ /* Death loop */
+ local_irq_disable();
+ while (__get_cpu_var(cpu_die))
+ cpu_relax();
+ local_irq_enable();
+
+ /* Now, we missed any cache flush IPIs, so be safe. */
+ local_flush_tlb();
+
+ /* Ack it by setting online bit */
+ br_write_lock_irq(BR_CPU_LOCK);
+ set_bit(smp_processor_id(), &cpu_online_map);
+ br_write_unlock_irq(BR_CPU_LOCK);
+ printk("Cpu %u arisen\n", smp_processor_id());
+ }
+}
+#else
+static inline void maybe_play_dead(void)
+{
+}
+#endif /*CONFIG_HOTPLUG*/
+
 /*
  * The idle thread. There's no useful work to be
  * done, so just try to conserve power and have a
@@ -141,8 +174,10 @@
                 if (!idle)
                         idle = default_idle;
                 irq_stat[smp_processor_id()].idle_timestamp = jiffies;
- while (!need_resched())
+ while (!need_resched()) {
+ maybe_play_dead();
                         idle();
+ }
                 schedule();
         }
 }
Index: linux-2.5.61-trojan/arch/i386/kernel/smp.c
===================================================================
RCS file: /build/cvsroot/linux-2.5.61/arch/i386/kernel/smp.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 smp.c
--- linux-2.5.61-trojan/arch/i386/kernel/smp.c 15 Feb 2003 12:32:09 -0000 1.1.1.1
+++ linux-2.5.61-trojan/arch/i386/kernel/smp.c 15 Feb 2003 19:31:05 -0000
@@ -19,6 +19,7 @@
 #include <linux/mc146818rtc.h>
 #include <linux/cache.h>
 #include <linux/interrupt.h>
+#include <linux/brlock.h>
 
 #include <asm/mtrr.h>
 #include <asm/pgalloc.h>
@@ -350,13 +351,18 @@
          */
         if (!cpumask)
                 BUG();
- if ((cpumask & cpu_online_map) != cpumask)
+ if ((cpumask & cpu_callout_map) != cpumask)
                 BUG();
         if (cpumask & (1 << smp_processor_id()))
                 BUG();
         if (!mm)
                 BUG();
 
+ /* CPUs might have gone offline: don't worry about them. */
+ cpumask &= cpu_online_map;
+ if (!cpumask)
+ return;
+
         /*
          * i'm not happy about this global shared spinlock in the
          * MM hot path, but we'll see how contended it is.
@@ -515,10 +521,15 @@
  */
 {
         struct call_data_struct data;
- int cpus = num_online_cpus()-1;
+ int cpus;
 
- if (!cpus)
+ br_read_lock(BR_CPU_LOCK);
+ cpus = num_online_cpus()-1;
+
+ if (!cpus) {
+ br_read_unlock(BR_CPU_LOCK);
                 return 0;
+ }
 
         data.func = func;
         data.info = info;
@@ -542,6 +553,7 @@
                         barrier();
         spin_unlock(&call_lock);
 
+ br_read_unlock(BR_CPU_LOCK);
         return 0;
 }
 
Index: linux-2.5.61-trojan/arch/i386/kernel/smpboot.c
===================================================================
RCS file: /build/cvsroot/linux-2.5.61/arch/i386/kernel/smpboot.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 smpboot.c
--- linux-2.5.61-trojan/arch/i386/kernel/smpboot.c 15 Feb 2003 12:32:09 -0000 1.1.1.1
+++ linux-2.5.61-trojan/arch/i386/kernel/smpboot.c 16 Feb 2003 19:56:16 -0000
@@ -45,6 +45,8 @@
 
 #include <linux/delay.h>
 #include <linux/mc146818rtc.h>
+#include <linux/brlock.h>
+#include <linux/percpu.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 #include <asm/desc.h>
@@ -64,9 +66,10 @@
 /* Bitmask of currently online CPUs */
 unsigned long cpu_online_map;
 
-static volatile unsigned long cpu_callin_map;
+/* Initialize, although master cpu never calls in */
+static volatile unsigned long cpu_callin_map = 1;
 volatile unsigned long cpu_callout_map;
-static unsigned long smp_commenced_mask;
+static unsigned long smp_commenced_mask = 1;
 
 /* Per CPU bogomips and other parameters */
 struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
@@ -456,7 +461,9 @@
          * the local TLBs too.
          */
         local_flush_tlb();
+ br_write_lock_irq(BR_CPU_LOCK);
         set_bit(smp_processor_id(), &cpu_online_map);
+ br_write_unlock_irq(BR_CPU_LOCK);
         wmb();
         return cpu_idle();
 }
@@ -1130,10 +1136,11 @@
         set_bit(smp_processor_id(), &cpu_callout_map);
 }
 
+DEFINE_PER_CPU(int, cpu_die) = { 0 };
+
 int __devinit __cpu_up(unsigned int cpu)
 {
- /* This only works at boot for x86. See "rewrite" above. */
- if (test_bit(cpu, &smp_commenced_mask)) {
+ if (test_bit(cpu, &smp_commenced_mask) && cpu_online(cpu)) {
                 local_irq_enable();
                 return -ENOSYS;
         }
@@ -1144,12 +1151,61 @@
                 return -EIO;
         }
 
+ /* Already up, and in maybe_play_dead now? */
+ if (test_bit(cpu, &smp_commenced_mask)) {
+ per_cpu(cpu_die, cpu) = 0;
+ wmb();
+ wake_idle_cpu(cpu);
+ while (!cpu_online(cpu))
+ yield();
+ printk("Cpu %u says it's online\n", cpu);
+ return 0;
+ }
+
         local_irq_enable();
         /* Unleash the CPU! */
         set_bit(cpu, &smp_commenced_mask);
         while (!test_bit(cpu, &cpu_online_map))
                 mb();
         return 0;
+}
+
+int __cpu_disable(void)
+{
+ br_write_lock_irq(BR_CPU_LOCK);
+ cpu_online_map &= ~(1UL << smp_processor_id());
+ br_write_unlock_irq(BR_CPU_LOCK);
+
+ printk("Disabled cpu %u\n", smp_processor_id());
+ return 0;
+}
+
+extern void migrate_irqs_from(unsigned int cpu);
+
+void __cpu_die(unsigned int cpu)
+{
+ unsigned int start;
+
+ /* Final threads can take some time to actually clean up */
+ while (!idle_cpu(cpu))
+ yield();
+
+ /* The irq affinity code is generic, now we just need a kernel/irq.c
+ * notice that we don't add it again on cpu_up, this is to avoid
+ * botching up current affinity and it would have to be moved later
+ * since we can't do this at boot hmm FIXME... -Zwane */
+ migrate_irqs_from(cpu);
+
+ per_cpu(cpu_die, cpu) = 1;
+ wmb();
+ for (start = jiffies; time_before(jiffies, start + HZ); ) {
+ wake_idle_cpu(cpu);
+ /* They ack this in maybe_play_dead by incrementing it. */
+ if (per_cpu(cpu_die, cpu) == 2)
+ return;
+ yield();
+ }
+ printk(KERN_ERR "CPU %u didn't die...\n", cpu);
 }
 
 void __init smp_cpus_done(unsigned int max_cpus)
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Sun Feb 23 2003 - 22:00:16 EST