Hotplug CPU boot (retransmit).
Subsystems (3)
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
@@ -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
@@ -150,7 +150,6 @@ extern void update_process_times(int useextern 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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.