Skip to contentSkip to conversation

Hotplug CPU boot (retransmit).

PATCH New Rusty Russell 1 participant 1 message Jul 26, 2002

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Hotplug CPU boot (retransmit).

As per Linus' earlier request, redoes the boot sequence to move towards hotplug (see details).

Only i386 and PPC converted: boot code changes best left to arch maintainers.

Thanks,
Rusty.

Name: Hot-plug CPU Boot Changes
Author: Rusty Russell
Status: Tested on 2.5.25, x86 SMP

D: This patch alters the boot sequence to "plug in" each CPU, one at a
D: time.  You need the patch for each architecture, as well.  The
D: interface used to be "smp_boot_cpus()", "smp_commence()", and each
D: arch implemented the "maxcpus" boot arg itself.  With this patch,
D: it is:
D:   smp_prepare_cpus(maxcpus): probe for cpus and set up cpu_possible(cpu).
D:   __cpu_up(cpu): called *after* initcalls, for each cpu where
D:      cpu_possible(cpu) is true.
D:   smp_cpus_done(maxcpus): called after every cpu has been brought up
include/linux/notifier.h +2 -0
diff -urpN -I \$.*\$ --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.5.27.1170/include/linux/notifier.h linux-2.5.27.1170.updated/include/linux/notifier.h
@@ -60,5 +60,7 @@ extern int notifier_call_chain(struct no
 
 #define NETLINK_URELEASE	0x0001	/* Unicast netlink socket released */
 
+#define CPU_ONLINE	0x0002 /* CPU (unsigned)v coming up */
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_NOTIFIER_H */
include/linux/sched.h +0 -1
diff -urpN -I \$.*\$ --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.5.27.1170/include/linux/sched.h linux-2.5.27.1170.updated/include/linux/sched.h
@@ -150,7 +150,6 @@ extern void update_process_times(int use
 extern void update_one_process(struct task_struct *p, unsigned long user,
 			       unsigned long system, int cpu);
 extern void scheduler_tick(int user_tick, int system);
-extern void migration_init(void);
 extern unsigned long cache_decay_ticks;
 
 
include/linux/smp.h +17 -6
diff -urpN -I \$.*\$ --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.5.27.1170/include/linux/smp.h linux-2.5.27.1170.updated/include/linux/smp.h
@@ -32,19 +32,19 @@ extern void FASTCALL(smp_send_reschedule
 
 
 /*
- * Boot processor call to load the other CPU's
+ * Prepare machine for booting other CPUs.
  */
-extern void smp_boot_cpus(void);
+extern void smp_prepare_cpus(unsigned int max_cpus);
 
 /*
- * Processor call in. Must hold processors until ..
+ * Bring a CPU up
  */
-extern void smp_callin(void);
+extern int __cpu_up(unsigned int cpunum);
 
 /*
- * Multiprocessors may now schedule
+ * Final polishing of CPUs
  */
-extern void smp_commence(void);
+extern void smp_cpus_done(unsigned int max_cpus);
 
 /*
  * Call a function on all other processors
@@ -71,6 +71,13 @@ extern volatile int smp_msg_id;
 #define MSG_RESCHEDULE		0x0003	/* Reschedule request from master CPU*/
 #define MSG_CALL_FUNCTION       0x0004  /* Call function on all other CPUs */
 
+struct notifier_block;
+
+/* Need to know about CPUs going up/down? */
+extern int register_cpu_notifier(struct notifier_block *nb);
+extern void unregister_cpu_notifier(struct notifier_block *nb);
+
+int cpu_up(unsigned int cpu);
 #else /* !SMP */
 
 /*
@@ -92,6 +99,10 @@ static inline void smp_send_reschedule_a
 #define __per_cpu_data
 #define per_cpu(var, cpu)			var
 #define this_cpu(var)				var
+
+/* Need to know about CPUs going up/down? */
+#define register_cpu_notifier(nb) 0
+#define unregister_cpu_notifier(nb) do { } while(0)
 
 #endif /* !SMP */
 
init/main.c +51 -10

107 lines not on this page · raw message

kernel/Makefile +1 -0
diff -urpN -I \$.*\$ --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.5.27.1170/kernel/Makefile linux-2.5.27.1170.updated/kernel/Makefile
@@ -17,6 +17,7 @@ obj-y     = sched.o dma.o fork.o exec_do
 	    sysctl.o capability.o ptrace.o timer.o user.o \
 	    signal.o sys.o kmod.o context.o futex.o platform.o
 
+obj-$(CONFIG_SMP) += cpu.o
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += ksyms.o
 obj-$(CONFIG_PM) += pm.o
kernel/cpu.c +54 -0

54 lines not on this page · raw message

kernel/sched.c +28 -30

93 lines not on this page · raw message

kernel/softirq.c +25 -12
diff -urpN -I \$.*\$ --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.5.27.1170/kernel/softirq.c linux-2.5.27.1170.updated/kernel/softirq.c
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/tqueue.h>
 #include <linux/percpu.h>
+#include <linux/notifier.h>
 
 /*
    - No shared variables, all the data are CPU local.
@@ -397,20 +398,32 @@ static int ksoftirqd(void * __bind_cpu)
 	}
 }
 
-static __init int spawn_ksoftirqd(void)
+static int __devinit cpu_callback(struct notifier_block *nfb,
+				  unsigned long action,
+				  void *hcpu)
 {
-	int cpu;
+	int hotcpu = (unsigned long)hcpu;
 
-	for (cpu = 0; cpu < NR_CPUS; cpu++) {
-		if (!cpu_online(cpu))
-			continue;
-		if (kernel_thread(ksoftirqd, (void *) (long) cpu,
-				  CLONE_FS | CLONE_FILES | CLONE_SIGNAL) < 0)
-			printk("spawn_ksoftirqd() failed for cpu %d\n", cpu);
-		else
-			while (!ksoftirqd_task(cpu))
-				yield();
-	}
+	if (action == CPU_ONLINE) {
+		if (kernel_thread(ksoftirqd, hcpu,
+				  CLONE_FS | CLONE_FILES | CLONE_SIGNAL) < 0) {
+			printk("ksoftirqd for %i failed\n", hotcpu);
+			return NOTIFY_BAD;
+		}
+
+		while (!ksoftirqd_task(hotcpu))
+			yield();
+		return NOTIFY_OK;
+ 	}
+	return NOTIFY_BAD;
+}
+
+static struct notifier_block cpu_nfb = { &cpu_callback, NULL, 0 };
+
+static __init int spawn_ksoftirqd(void)
+{
+	cpu_callback(&cpu_nfb, CPU_ONLINE, (void *)smp_processor_id());
+	register_cpu_notifier(&cpu_nfb);
 	return 0;
 }
 

Name: Hot-plug CPU Boot Rewrite for i386
Author: Rusty Russell
Status: Tested 2.5.25, dual SMP
Depends: Hotcpu/hotcpu-boot.patch.gz

D: This modifies the i386 boot sequence to "plug in" CPUs one at a
D: time. This is the minimal change to make it work (the CPUs are
D: brought up as normal during the "smp_prepare_cpus()" probe phase).

arch/i386/kernel/apic.c +11 -7
diff -urN -I \$.*\$ --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5.25/arch/i386/kernel/apic.c working-2.5.25-hotcpu/arch/i386/kernel/apic.c
@@ -798,9 +798,9 @@
 	apic_write_around(APIC_TMICT, clocks/APIC_DIVISOR);
 }
 
-void setup_APIC_timer(void * data)
+static void setup_APIC_timer(unsigned int clocks)
 {
-	unsigned int clocks = (unsigned int) data, slice, t0, t1;
+	unsigned int slice, t0, t1;
 	unsigned long flags;
 	int delta;
 
@@ -926,7 +926,7 @@
 
 int dont_use_local_apic_timer __initdata = 0;
 
-void __init setup_APIC_clocks (void)
+void __init setup_boot_APIC_clock(void)
 {
 	/* Disabled by DMI scan or kernel option? */
 	if (dont_use_local_apic_timer)
@@ -941,12 +941,16 @@
 	/*
 	 * Now set up the timer for real.
 	 */
-	setup_APIC_timer((void *)calibration_result);
+	setup_APIC_timer(calibration_result);
 
 	__sti();
+}
 
-	/* and update all other cpus */
-	smp_call_function(setup_APIC_timer, (void *)calibration_result, 1, 1);
+void __init setup_secondary_APIC_clock(void)
+{
+	__cli(); /* FIXME: Do we need this? --RR */
+	setup_APIC_timer(calibration_result);
+	__sti();
 }
 
 void __init disable_APIC_timer(void)
@@ -1178,7 +1182,7 @@
 		if (!skip_ioapic_setup && nr_ioapics)
 			setup_IO_APIC();
 #endif
-	setup_APIC_clocks();
+	setup_boot_APIC_clock();
 
 	return 0;
 }
arch/i386/kernel/apm.c +5 -9
diff -urN -I \$.*\$ --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5.25/arch/i386/kernel/apm.c working-2.5.25-hotcpu/arch/i386/kernel/apm.c
@@ -1587,7 +1587,7 @@
 
 	p = buf;
 
-	if ((num_online_cpus() == 1) &&
+	if ((num_possible_cpus() == 1) &&
 	    !(error = apm_get_power_status(&bx, &cx, &dx))) {
 		ac_line_status = (bx >> 8) & 0xff;
 		battery_status = bx & 0xff;
@@ -1718,7 +1718,7 @@
 		}
 	}
 
-	if (debug && (num_online_cpus() == 1)) {
+	if (debug && (num_possible_cpus() == 1)) {
 		error = apm_get_power_status(&bx, &cx, &dx);
 		if (error)
 			printk(KERN_INFO "apm: power status not available\n");
@@ -1762,7 +1762,7 @@
 		pm_power_off = apm_power_off;
 	register_sysrq_key('o', &sysrq_poweroff_op);
 
-	if (num_online_cpus() == 1) {
+	if (num_possible_cpus() == 1) {
 #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
 		console_blank_hook = apm_console_blank;
 #endif
@@ -1905,9 +1905,7 @@
 		printk(KERN_NOTICE "apm: disabled on user request.\n");
 		return -ENODEV;
 	}
-	/* FIXME: When boot code changes, this will need to be
-           deactivated when/if a CPU comes up --RR */
-	if ((num_online_cpus() > 1) && !power_off) {
+	if ((num_possible_cpus() > 1) && !power_off) {
 		printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
 		return -ENODEV;
 	}
@@ -1961,9 +1959,7 @@
 
 	kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
 
-	/* FIXME: When boot code changes, this will need to be
-           deactivated when/if a CPU comes up --RR */
-	if (num_online_cpus() > 1) {
+	if (num_possible_cpus() > 1) {
 		printk(KERN_NOTICE
 		   "apm: disabled - APM is not SMP safe (power off active).\n");
 		return 0;
arch/i386/kernel/mtrr.c +3 -3
diff -urN -I \$.*\$ --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5.25/arch/i386/kernel/mtrr.c working-2.5.25-hotcpu/arch/i386/kernel/mtrr.c
@@ -1055,7 +1055,7 @@
     wait_barrier_cache_disable = TRUE;
     wait_barrier_execute = TRUE;
     wait_barrier_cache_enable = TRUE;
-    atomic_set (&undone_count, num_online_cpus() - 1);
+    atomic_set (&undone_count, num_booting_cpus() - 1);
     /*  Start the ball rolling on other CPUs  */
     if (smp_call_function (ipi_handler, &data, 1, 0) != 0)
 	panic ("mtrr: timed out waiting for other CPUs\n");
@@ -1064,14 +1064,14 @@
     /*  Wait for all other CPUs to flush and disable their caches  */
     while (atomic_read (&undone_count) > 0) { rep_nop(); barrier(); }
     /* Set up for completion wait and then release other CPUs to change MTRRs*/
-    atomic_set (&undone_count, num_online_cpus() - 1);
+    atomic_set (&undone_count, num_booting_cpus() - 1);
     wait_barrier_cache_disable = FALSE;
     set_mtrr_cache_disable (&ctxt);
 
     /*  Wait for all other CPUs to flush and disable their caches  */
     while (atomic_read (&undone_count) > 0) { rep_nop(); barrier(); }
     /* Set up for completion wait and then release other CPUs to change MTRRs*/
-    atomic_set (&undone_count, num_online_cpus() - 1);
+    atomic_set (&undone_count, num_booting_cpus() - 1);
     wait_barrier_execute = FALSE;
     (*set_mtrr_up) (reg, base, size, type, FALSE);
     /*  Now wait for other CPUs to complete the function  */
arch/i386/kernel/nmi.c +2 -0
diff -urN -I \$.*\$ --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5.25/arch/i386/kernel/nmi.c working-2.5.25-hotcpu/arch/i386/kernel/nmi.c
@@ -81,6 +81,8 @@
 	sti();
 	mdelay((10*1000)/nmi_hz); // wait 10 ticks
 
+	/* FIXME: Only boot CPU is online at this stage.  Check CPUs
+           as they come up. */
 	for (cpu = 0; cpu < NR_CPUS; cpu++) {
 		if (!cpu_online(cpu))
 			continue;
arch/i386/kernel/smpboot.c +57 -84

310 lines not on this page · raw message

include/asm-i386/apic.h +2 -1
diff -urN -I \$.*\$ --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5.25/include/asm-i386/apic.h working-2.5.25-hotcpu/include/asm-i386/apic.h
@@ -76,7 +76,8 @@
 extern void setup_local_APIC (void);
 extern void init_apic_mappings (void);
 extern void smp_local_timer_interrupt (struct pt_regs * regs);
-extern void setup_APIC_clocks (void);
+extern void setup_boot_APIC_clock (void);
+extern void setup_secondary_APIC_clock (void);
 extern void setup_apic_nmi_watchdog (void);
 extern inline void nmi_watchdog_tick (struct pt_regs * regs);
 extern int APIC_init_uniprocessor (void);
include/asm-i386/smp.h +8 -7
diff -urN -I \$.*\$ --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5.25/include/asm-i386/smp.h working-2.5.25-hotcpu/include/asm-i386/smp.h
@@ -79,19 +79,13 @@
 extern volatile int logical_apicid_to_cpu[MAX_APICID];
 
 /*
- * General functions that each host system must provide.
- */
- 
-extern void smp_boot_cpus(void);
-extern void smp_store_cpu_info(int id);		/* Store per CPU info (like the initial udelay numbers */
-
-/*
  * 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(),
  * so this is correct in the x86 case.
  */
 #define smp_processor_id() (current_thread_info()->cpu)
 
+#define cpu_possible(cpu) (phys_cpu_present_map & (1<<(cpu)))
 #define cpu_online(cpu) (cpu_online_map & (1<<(cpu)))
 
 extern inline unsigned int num_online_cpus(void)
@@ -117,6 +111,13 @@
 {
 	/* we don't want to mark this access volatile - bad code generation */
 	return GET_APIC_LOGICAL_ID(*(unsigned long *)(APIC_BASE+APIC_LDR));
+}
+
+extern volatile unsigned long cpu_callout_map;
+/* We don't mark CPUs online until __cpu_up(), so we need another measure */
+static inline int num_booting_cpus(void)
+{
+	return hweight32(cpu_callout_map);
 }
 
 #endif /* !__ASSEMBLY__ */

Name: Hot-plug CPU Boot Rewrite for PPC
Author: Rusty Russell
Status: Tested on 2.5.15/PPC
Depends: Hotcpu/hotcpu-boot.patch.gz

D: This modifies the PPC boot sequence to "plug in" CPUs one at a
D: time.

arch/ppc/kernel/open_pic.c +1 -1
diff -urN -I \$.*\$ --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal working-ppc-2.5-pre-hotcpu/arch/ppc/kernel/open_pic.c working-ppc-2.5-hotcpu/arch/ppc/kernel/open_pic.c
@@ -603,7 +603,7 @@
  *   -- Cort
  */
 
-void __init do_openpic_setup_cpu(void)
+void __devinit do_openpic_setup_cpu(void)
 {
  	int i;
 	u32 msk = 1 << smp_hw_index[smp_processor_id()];
arch/ppc/kernel/smp.c +162 -10

196 lines not on this page · raw message

arch/ppc/platforms/chrp_smp.c +43 -41

102 lines not on this page · raw message

arch/ppc/platforms/gemini_setup.c +2 -0
diff -urN -I \$.*\$ --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal working-ppc-2.5-pre-hotcpu/arch/ppc/platforms/gemini_setup.c working-ppc-2.5-hotcpu/arch/ppc/platforms/gemini_setup.c
@@ -527,6 +527,8 @@
 	smp_gemini_probe,
 	smp_gemini_kick_cpu,
 	smp_gemini_setup_cpu,
+	.give_timebase = smp_generic_give_timebase,
+	.take_timebase = smp_generic_take_timebase,
 };
 #endif /* CONFIG_SMP */
 
arch/ppc/platforms/iSeries_smp.c +5 -2
diff -urN -I \$.*\$ --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal working-ppc-2.5-pre-hotcpu/arch/ppc/platforms/iSeries_smp.c working-ppc-2.5-hotcpu/arch/ppc/platforms/iSeries_smp.c
@@ -117,7 +117,7 @@
 	set_dec( xPaca[nr].default_decr );
 }
 
-void smp_iSeries_space_timers( unsigned nr )
+static void smp_iSeries_space_timers(unsigned nr)
 {
 	unsigned offset,i;
 	
@@ -131,6 +131,9 @@
    smp_iSeries_message_pass,
    smp_iSeries_probe,
    smp_iSeries_kick_cpu,
-   smp_iSeries_setup_cpu
+   smp_iSeries_setup_cpu,
+   smp_iSeries_space_timers,
+   .give_timebase = smp_generic_give_timebase,
+   .take_timebase = smp_generic_take_timebase,
 };
 
arch/ppc/platforms/pmac_smp.c +4 -0
diff -urN -I \$.*\$ --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal working-ppc-2.5-pre-hotcpu/arch/ppc/platforms/pmac_smp.c working-ppc-2.5-hotcpu/arch/ppc/platforms/pmac_smp.c
@@ -612,6 +612,8 @@
 	smp_psurge_probe,
 	smp_psurge_kick_cpu,
 	smp_psurge_setup_cpu,
+	.give_timebase = smp_generic_give_timebase,
+	.take_timebase = smp_generic_take_timebase,
 };
 
 /* Core99 Macs (dual G4s) */
@@ -620,4 +622,6 @@
 	smp_core99_probe,
 	smp_core99_kick_cpu,
 	smp_core99_setup_cpu,
+	.give_timebase = smp_generic_give_timebase,
+	.take_timebase = smp_generic_take_timebase,
 };
arch/ppc/platforms/pplus_setup.c +2 -0
diff -urN -I \$.*\$ --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal working-ppc-2.5-pre-hotcpu/arch/ppc/platforms/pplus_setup.c working-ppc-2.5-hotcpu/arch/ppc/platforms/pplus_setup.c
@@ -318,6 +318,8 @@
 	smp_pplus_probe,
 	smp_pplus_kick_cpu,
 	smp_pplus_setup_cpu,
+	.give_timebase = smp_generic_give_timebase,
+	.take_timebase = smp_generic_take_timebase,
 };
 #endif /* CONFIG_SMP */
 
arch/ppc/platforms/prep_setup.c +2 -0
diff -urN -I \$.*\$ --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal working-ppc-2.5-pre-hotcpu/arch/ppc/platforms/prep_setup.c working-ppc-2.5-hotcpu/arch/ppc/platforms/prep_setup.c
@@ -765,6 +765,8 @@
 	smp_prep_probe,
 	smp_prep_kick_cpu,
 	smp_prep_setup_cpu,
+	.give_timebase = smp_generic_give_timebase,
+	.take_timebase = smp_generic_take_timebase,
 };
 #endif /* CONFIG_SMP */
 
include/asm-ppc/machdep.h +8 -0
diff -urN -I \$.*\$ --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal working-ppc-2.5-pre-hotcpu/include/asm-ppc/machdep.h working-ppc-2.5-hotcpu/include/asm-ppc/machdep.h
@@ -6,6 +6,7 @@
 #define _PPC_MACHDEP_H
 
 #include <linux/config.h>
+#include <linux/init.h>
 
 #ifdef CONFIG_APUS
 #include <asm-m68k/machdep.h>
@@ -135,7 +136,14 @@
 	int   (*probe)(void);
 	void  (*kick_cpu)(int nr);
 	void  (*setup_cpu)(int nr);
+	void  (*space_timers)(int nr);
+	void  (*take_timebase)(void);
+	void  (*give_timebase)(void);
 };
+
+/* Poor default implementations */
+extern void __devinit smp_generic_give_timebase(void);
+extern void __devinit smp_generic_take_timebase(void);
 #endif /* CONFIG_SMP */
 
 #endif /* _PPC_MACHDEP_H */
include/asm-ppc/smp.h +5 -1
diff -urN -I \$.*\$ --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal working-ppc-2.5-pre-hotcpu/include/asm-ppc/smp.h working-ppc-2.5-hotcpu/include/asm-ppc/smp.h
@@ -16,6 +16,7 @@
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/bitops.h>
+#include <linux/errno.h>
 
 #ifdef CONFIG_SMP
 
@@ -31,11 +32,11 @@
 
 extern struct cpuinfo_PPC cpu_data[];
 extern unsigned long cpu_online_map;
+extern unsigned long cpu_possible_map;
 extern unsigned long smp_proc_in_lock[];
 extern volatile unsigned long cpu_callin_map[];
 extern int smp_tb_synchronized;
 
-extern void smp_store_cpu_info(int id);
 extern void smp_send_tlb_invalidate(int);
 extern void smp_send_xmon_break(int cpu);
 struct pt_regs;
@@ -48,6 +49,7 @@
 #define smp_processor_id() (current_thread_info()->cpu)
 
 #define cpu_online(cpu) (cpu_online_map & (1<<(cpu)))
+#define cpu_possible(cpu) (cpu_possible_map & (1<<(cpu)))
 
 extern inline unsigned int num_online_cpus(void)
 {
@@ -61,6 +63,8 @@
 
 	return -1;
 }
+
+extern int __cpu_up(unsigned int cpu);
 
 extern int smp_hw_index[];
 #define hard_smp_processor_id() (smp_hw_index[smp_processor_id()])

--
Anyone who quotes me in their sig is an idiot. -- Rusty Russell.