ia64/xen-unstable

changeset 4749:9c9be1b0e3b1

bitkeeper revision 1.1389.1.35 (42778db85KaZKAK6OU1HQjCb_K-YKw)

Merge firebug.cl.cam.ac.uk:/auto/groups/xeno-xenod/BK/xen-unstable.bk
into firebug.cl.cam.ac.uk:/local/scratch/cl349/xen-unstable.bk
author cl349@firebug.cl.cam.ac.uk
date Tue May 03 14:42:00 2005 +0000 (2005-05-03)
parents d8a9ad9290ac 819bea630a17
children 487de0451d2b
files .rootkeys linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig linux-2.6.11-xen-sparse/arch/xen/i386/Makefile linux-2.6.11-xen-sparse/arch/xen/i386/kernel/irq.c linux-2.6.11-xen-sparse/arch/xen/i386/kernel/process.c linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smp.c linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c linux-2.6.11-xen-sparse/arch/xen/i386/kernel/traps.c linux-2.6.11-xen-sparse/arch/xen/i386/mach-default/Makefile patches/linux-2.6.11/i386-cpu-hotplug-updated-for-mm.patch
line diff
     1.1 --- a/.rootkeys	Tue May 03 14:27:54 2005 +0000
     1.2 +++ b/.rootkeys	Tue May 03 14:42:00 2005 +0000
     1.3 @@ -248,6 +248,7 @@ 40f56238BMqG5PuSHufpjbvp_helBw linux-2.6
     1.4  40f562389xNa78YBZciUibQjyRU_Lg linux-2.6.11-xen-sparse/arch/xen/i386/kernel/traps.c
     1.5  40f56238JypKAUG01ZojFwH7qnZ5uA linux-2.6.11-xen-sparse/arch/xen/i386/kernel/vsyscall.S
     1.6  40f56238wi6AdNQjm0RT57bSkwb6hg linux-2.6.11-xen-sparse/arch/xen/i386/kernel/vsyscall.lds
     1.7 +427245dboQBkhq841wIPqlRD-AG9Jw linux-2.6.11-xen-sparse/arch/xen/i386/mach-default/Makefile
     1.8  40f56238a3w6-byOzexIlMgni76Lcg linux-2.6.11-xen-sparse/arch/xen/i386/mm/Makefile
     1.9  40f56238ILx8xlbywNbzTdv5Zr4xXQ linux-2.6.11-xen-sparse/arch/xen/i386/mm/fault.c
    1.10  4118cc35CbY8rfGVspF5O-7EkXBEAA linux-2.6.11-xen-sparse/arch/xen/i386/mm/highmem.c
    1.11 @@ -466,6 +467,7 @@ 422e4430vKaHLOOGS7X-SUUe3EBCgw netbsd-2.
    1.12  422e4430-gOD358H8nGGnNWes08Nng netbsd-2.0-xen-sparse/sys/miscfs/kernfs/kernfs_vnops.c
    1.13  413cb3b53nyOv1OIeDSsCXhBFDXvJA netbsd-2.0-xen-sparse/sys/nfs/files.nfs
    1.14  413aa1d0oNP8HXLvfPuMe6cSroUfSA patches/linux-2.6.11/agpgart.patch
    1.15 +427261074Iy1MkbbqIV6zdZDWWx_Jg patches/linux-2.6.11/i386-cpu-hotplug-updated-for-mm.patch
    1.16  42372652KCUP-IOH9RN19YQmGhs4aA patches/linux-2.6.11/iomap.patch
    1.17  424f001e_M1Tnxc52rDrmCLelnDWMQ patches/linux-2.6.11/x86_64-linux.patch
    1.18  3f776bd1Hy9rn69ntXBhPReUFw9IEA tools/Makefile
     2.1 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig	Tue May 03 14:27:54 2005 +0000
     2.2 +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig	Tue May 03 14:42:00 2005 +0000
     2.3 @@ -672,6 +672,16 @@ config X86_IO_APIC
     2.4  	depends on !SMP && X86_UP_IOAPIC
     2.5  	default y
     2.6  
     2.7 +config HOTPLUG_CPU
     2.8 +	bool "Support for hot-pluggable CPUs (EXPERIMENTAL)"
     2.9 +	depends on SMP && HOTPLUG && EXPERIMENTAL
    2.10 +	---help---
    2.11 +	  Say Y here to experiment with turning CPUs off and on.  CPUs
    2.12 +	  can be controlled through /sys/devices/system/cpu.
    2.13 +
    2.14 +	  Say N.
    2.15 +
    2.16 +
    2.17  if XEN_PHYSDEV_ACCESS
    2.18  
    2.19  menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)"
     3.1 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/Makefile	Tue May 03 14:27:54 2005 +0000
     3.2 +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/Makefile	Tue May 03 14:42:00 2005 +0000
     3.3 @@ -72,6 +72,7 @@ head-y := arch/xen/i386/kernel/head.o ar
     3.4  libs-y 					+= arch/i386/lib/
     3.5  core-y					+= arch/xen/i386/kernel/ \
     3.6  					   arch/xen/i386/mm/ \
     3.7 +					   arch/xen/i386/mach-default/ \
     3.8  					   arch/i386/crypto/
     3.9  # \
    3.10  #					   arch/xen/$(mcore-y)/
     4.1 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/irq.c	Tue May 03 14:27:54 2005 +0000
     4.2 +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/irq.c	Tue May 03 14:42:00 2005 +0000
     4.3 @@ -15,6 +15,9 @@
     4.4  #include <linux/seq_file.h>
     4.5  #include <linux/interrupt.h>
     4.6  #include <linux/kernel_stat.h>
     4.7 +#include <linux/notifier.h>
     4.8 +#include <linux/cpu.h>
     4.9 +#include <linux/delay.h>
    4.10  
    4.11  #ifndef CONFIG_X86_LOCAL_APIC
    4.12  /*
    4.13 @@ -207,9 +210,8 @@ int show_interrupts(struct seq_file *p, 
    4.14  
    4.15  	if (i == 0) {
    4.16  		seq_printf(p, "           ");
    4.17 -		for (j=0; j<NR_CPUS; j++)
    4.18 -			if (cpu_online(j))
    4.19 -				seq_printf(p, "CPU%d       ",j);
    4.20 +		for_each_cpu(j)
    4.21 +			seq_printf(p, "CPU%d       ",j);
    4.22  		seq_putc(p, '\n');
    4.23  	}
    4.24  
    4.25 @@ -222,9 +224,8 @@ int show_interrupts(struct seq_file *p, 
    4.26  #ifndef CONFIG_SMP
    4.27  		seq_printf(p, "%10u ", kstat_irqs(i));
    4.28  #else
    4.29 -		for (j = 0; j < NR_CPUS; j++)
    4.30 -			if (cpu_online(j))
    4.31 -				seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
    4.32 +		for_each_cpu(j)
    4.33 +			seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
    4.34  #endif
    4.35  		seq_printf(p, " %14s", irq_desc[i].handler->typename);
    4.36  		seq_printf(p, "  %s", action->name);
    4.37 @@ -237,16 +238,13 @@ skip:
    4.38  		spin_unlock_irqrestore(&irq_desc[i].lock, flags);
    4.39  	} else if (i == NR_IRQS) {
    4.40  		seq_printf(p, "NMI: ");
    4.41 -		for (j = 0; j < NR_CPUS; j++)
    4.42 -			if (cpu_online(j))
    4.43 -				seq_printf(p, "%10u ", nmi_count(j));
    4.44 +		for_each_cpu(j)
    4.45 +			seq_printf(p, "%10u ", nmi_count(j));
    4.46  		seq_putc(p, '\n');
    4.47  #ifdef CONFIG_X86_LOCAL_APIC
    4.48  		seq_printf(p, "LOC: ");
    4.49 -		for (j = 0; j < NR_CPUS; j++)
    4.50 -			if (cpu_online(j))
    4.51 -				seq_printf(p, "%10u ",
    4.52 -					irq_stat[j].apic_timer_irqs);
    4.53 +		for_each_cpu(j)
    4.54 +			seq_printf(p, "%10u ", irq_stat[j].apic_timer_irqs);
    4.55  		seq_putc(p, '\n');
    4.56  #endif
    4.57  		seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
    4.58 @@ -256,3 +254,44 @@ skip:
    4.59  	}
    4.60  	return 0;
    4.61  }
    4.62 +
    4.63 +#ifdef CONFIG_HOTPLUG_CPU
    4.64 +
    4.65 +void fixup_irqs(cpumask_t map)
    4.66 +{
    4.67 +	unsigned int irq;
    4.68 +	static int warned;
    4.69 +
    4.70 +	for (irq = 0; irq < NR_IRQS; irq++) {
    4.71 +		cpumask_t mask;
    4.72 +		if (irq == 2)
    4.73 +			continue;
    4.74 +
    4.75 +		cpus_and(mask, irq_affinity[irq], map);
    4.76 +		if (any_online_cpu(mask) == NR_CPUS) {
    4.77 +			printk("Breaking affinity for irq %i\n", irq);
    4.78 +			mask = map;
    4.79 +		}
    4.80 +		if (irq_desc[irq].handler->set_affinity)
    4.81 +			irq_desc[irq].handler->set_affinity(irq, mask);
    4.82 +		else if (irq_desc[irq].action && !(warned++))
    4.83 +			printk("Cannot set affinity for irq %i\n", irq);
    4.84 +	}
    4.85 +
    4.86 +#if 0
    4.87 +	barrier();
    4.88 +	/* Ingo Molnar says: "after the IO-APIC masks have been redirected
    4.89 +	   [note the nop - the interrupt-enable boundary on x86 is two
    4.90 +	   instructions from sti] - to flush out pending hardirqs and
    4.91 +	   IPIs. After this point nothing is supposed to reach this CPU." */
    4.92 +	__asm__ __volatile__("sti; nop; cli");
    4.93 +	barrier();
    4.94 +#else
    4.95 +	/* That doesn't seem sufficient.  Give it 1ms. */
    4.96 +	local_irq_enable();
    4.97 +	mdelay(1);
    4.98 +	local_irq_disable();
    4.99 +#endif
   4.100 +}
   4.101 +#endif
   4.102 +
     5.1 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/process.c	Tue May 03 14:27:54 2005 +0000
     5.2 +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/process.c	Tue May 03 14:42:00 2005 +0000
     5.3 @@ -13,6 +13,7 @@
     5.4  
     5.5  #include <stdarg.h>
     5.6  
     5.7 +#include <linux/cpu.h>
     5.8  #include <linux/errno.h>
     5.9  #include <linux/sched.h>
    5.10  #include <linux/fs.h>
    5.11 @@ -54,6 +55,9 @@
    5.12  #include <linux/irq.h>
    5.13  #include <linux/err.h>
    5.14  
    5.15 +#include <asm/tlbflush.h>
    5.16 +#include <asm/cpu.h>
    5.17 +
    5.18  asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
    5.19  
    5.20  int hlt_counter;
    5.21 @@ -112,6 +116,33 @@ void xen_idle(void)
    5.22  	}
    5.23  }
    5.24  
    5.25 +#ifdef CONFIG_HOTPLUG_CPU
    5.26 +#include <asm/nmi.h>
    5.27 +/* We don't actually take CPU down, just spin without interrupts. */
    5.28 +static inline void play_dead(void)
    5.29 +{
    5.30 +	/* Ack it */
    5.31 +	__get_cpu_var(cpu_state) = CPU_DEAD;
    5.32 +
    5.33 +	/* We shouldn't have to disable interrupts while dead, but
    5.34 +	 * some interrupts just don't seem to go away, and this makes
    5.35 +	 * it "work" for testing purposes. */
    5.36 +	/* Death loop */
    5.37 +	while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE)
    5.38 +		HYPERVISOR_yield();
    5.39 +
    5.40 +	local_irq_disable();
    5.41 +	__flush_tlb_all();
    5.42 +	cpu_set(smp_processor_id(), cpu_online_map);
    5.43 +	local_irq_enable();
    5.44 +}
    5.45 +#else
    5.46 +static inline void play_dead(void)
    5.47 +{
    5.48 +	BUG();
    5.49 +}
    5.50 +#endif /* CONFIG_HOTPLUG_CPU */
    5.51 +
    5.52  /*
    5.53   * The idle thread. There's no useful work to be
    5.54   * done, so just try to conserve power and have a
    5.55 @@ -130,6 +161,9 @@ void cpu_idle (void)
    5.56  				cpu_clear(cpu, cpu_idle_map);
    5.57  			rmb();
    5.58  
    5.59 +			if (cpu_is_offline(cpu))
    5.60 +				play_dead();
    5.61 +
    5.62  			irq_stat[cpu].idle_timestamp = jiffies;
    5.63  			xen_idle();
    5.64  		}
     6.1 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smp.c	Tue May 03 14:27:54 2005 +0000
     6.2 +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smp.c	Tue May 03 14:42:00 2005 +0000
     6.3 @@ -19,6 +19,7 @@
     6.4  #include <linux/mc146818rtc.h>
     6.5  #include <linux/cache.h>
     6.6  #include <linux/interrupt.h>
     6.7 +#include <linux/cpu.h>
     6.8  
     6.9  #include <asm/mtrr.h>
    6.10  #include <asm/tlbflush.h>
    6.11 @@ -185,6 +186,7 @@ void send_IPI_mask_bitmask(cpumask_t mas
    6.12  	unsigned int cpu;
    6.13  
    6.14  	local_irq_save(flags);
    6.15 +	WARN_ON(cpus_addr(mask)[0] & ~cpus_addr(cpu_online_map)[0]);
    6.16  
    6.17  	for (cpu = 0; cpu < NR_CPUS; ++cpu) {
    6.18  		if (cpu_isset(cpu, mask)) {
    6.19 @@ -320,21 +322,21 @@ out:
    6.20  static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
    6.21  						unsigned long va)
    6.22  {
    6.23 -	cpumask_t tmp;
    6.24  	/*
    6.25  	 * A couple of (to be removed) sanity checks:
    6.26  	 *
    6.27 -	 * - we do not send IPIs to not-yet booted CPUs.
    6.28  	 * - current CPU must not be in mask
    6.29  	 * - mask must exist :)
    6.30  	 */
    6.31  	BUG_ON(cpus_empty(cpumask));
    6.32 -
    6.33 -	cpus_and(tmp, cpumask, cpu_online_map);
    6.34 -	BUG_ON(!cpus_equal(cpumask, tmp));
    6.35  	BUG_ON(cpu_isset(smp_processor_id(), cpumask));
    6.36  	BUG_ON(!mm);
    6.37  
    6.38 +	/* If a CPU which we ran on has gone down, OK. */
    6.39 +	cpus_and(cpumask, cpumask, cpu_online_map);
    6.40 +	if (cpus_empty(cpumask))
    6.41 +		return;
    6.42 +
    6.43  	/*
    6.44  	 * i'm not happy about this global shared spinlock in the
    6.45  	 * MM hot path, but we'll see how contended it is.
    6.46 @@ -465,6 +467,7 @@ void flush_tlb_all(void)
    6.47   */
    6.48  void smp_send_reschedule(int cpu)
    6.49  {
    6.50 +	WARN_ON(cpu_is_offline(cpu));
    6.51  	send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR);
    6.52  }
    6.53  
    6.54 @@ -505,10 +508,16 @@ int smp_call_function (void (*func) (voi
    6.55   */
    6.56  {
    6.57  	struct call_data_struct data;
    6.58 -	int cpus = num_online_cpus()-1;
    6.59 +	int cpus;
    6.60  
    6.61 -	if (!cpus)
    6.62 +	/* Holding any lock stops cpus from going down. */
    6.63 +	spin_lock(&call_lock);
    6.64 +	cpus = num_online_cpus()-1;
    6.65 +
    6.66 +	if (!cpus) {
    6.67 +		spin_unlock(&call_lock);
    6.68  		return 0;
    6.69 +	}
    6.70  
    6.71  	/* Can deadlock when called with interrupts disabled */
    6.72  	WARN_ON(irqs_disabled());
    6.73 @@ -520,7 +529,6 @@ int smp_call_function (void (*func) (voi
    6.74  	if (wait)
    6.75  		atomic_set(&data.finished, 0);
    6.76  
    6.77 -	spin_lock(&call_lock);
    6.78  	call_data = &data;
    6.79  	mb();
    6.80  	
     7.1 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c	Tue May 03 14:27:54 2005 +0000
     7.2 +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c	Tue May 03 14:42:00 2005 +0000
     7.3 @@ -44,6 +44,9 @@
     7.4  #include <linux/smp_lock.h>
     7.5  #include <linux/irq.h>
     7.6  #include <linux/bootmem.h>
     7.7 +#include <linux/notifier.h>
     7.8 +#include <linux/cpu.h>
     7.9 +#include <linux/percpu.h>
    7.10  
    7.11  #include <linux/delay.h>
    7.12  #include <linux/mc146818rtc.h>
    7.13 @@ -93,7 +96,14 @@ extern unsigned char trampoline_data [];
    7.14  extern unsigned char trampoline_end  [];
    7.15  static unsigned char *trampoline_base;
    7.16  static int trampoline_exec;
    7.17 +#endif
    7.18  
    7.19 +#ifdef CONFIG_HOTPLUG_CPU
    7.20 +/* State of each CPU. */
    7.21 +DEFINE_PER_CPU(int, cpu_state) = { 0 };
    7.22 +#endif
    7.23 +
    7.24 +#if 0
    7.25  /*
    7.26   * Currently trivial. Write the real->protected mode
    7.27   * bootstrap into the page concerned. The caller
    7.28 @@ -500,6 +510,7 @@ static int __init start_secondary(void *
    7.29  		}
    7.30  	}
    7.31  	cpu_idle();
    7.32 +	return 0;
    7.33  }
    7.34  
    7.35  /*
    7.36 @@ -1284,6 +1295,9 @@ static void __init smp_boot_cpus(unsigne
    7.37     who understands all this stuff should rewrite it properly. --RR 15/Jul/02 */
    7.38  void __init smp_prepare_cpus(unsigned int max_cpus)
    7.39  {
    7.40 +	smp_commenced_mask = cpumask_of_cpu(0);
    7.41 +	cpu_callin_map = cpumask_of_cpu(0);
    7.42 +	mb();
    7.43  	smp_boot_cpus(max_cpus);
    7.44  }
    7.45  
    7.46 @@ -1293,20 +1307,97 @@ void __devinit smp_prepare_boot_cpu(void
    7.47  	cpu_set(smp_processor_id(), cpu_callout_map);
    7.48  }
    7.49  
    7.50 +#ifdef CONFIG_HOTPLUG_CPU
    7.51 +
    7.52 +/* must be called with the cpucontrol mutex held */
    7.53 +static int __devinit cpu_enable(unsigned int cpu)
    7.54 +{
    7.55 +	/* get the target out of its holding state */
    7.56 +	per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
    7.57 +	wmb();
    7.58 +
    7.59 +	/* wait for the processor to ack it. timeout? */
    7.60 +	while (!cpu_online(cpu))
    7.61 +		cpu_relax();
    7.62 +
    7.63 +	fixup_irqs(cpu_online_map);
    7.64 +	/* counter the disable in fixup_irqs() */
    7.65 +	local_irq_enable();
    7.66 +	return 0;
    7.67 +}
    7.68 +
    7.69 +int __cpu_disable(void)
    7.70 +{
    7.71 +	cpumask_t map = cpu_online_map;
    7.72 +	int cpu = smp_processor_id();
    7.73 +
    7.74 +	/*
    7.75 +	 * Perhaps use cpufreq to drop frequency, but that could go
    7.76 +	 * into generic code.
    7.77 + 	 *
    7.78 +	 * We won't take down the boot processor on i386 due to some
    7.79 +	 * interrupts only being able to be serviced by the BSP.
    7.80 +	 * Especially so if we're not using an IOAPIC	-zwane
    7.81 +	 */
    7.82 +	if (cpu == 0)
    7.83 +		return -EBUSY;
    7.84 +
    7.85 +	/* Allow any queued timer interrupts to get serviced */
    7.86 +	local_irq_enable();
    7.87 +	mdelay(1);
    7.88 +	local_irq_disable();
    7.89 +
    7.90 +	cpu_clear(cpu, map);
    7.91 +	fixup_irqs(map);
    7.92 +	/* It's now safe to remove this processor from the online map */
    7.93 +	cpu_clear(cpu, cpu_online_map);
    7.94 +	return 0;
    7.95 +}
    7.96 +
    7.97 +void __cpu_die(unsigned int cpu)
    7.98 +{
    7.99 +	/* We don't do anything here: idle task is faking death itself. */
   7.100 +	unsigned int i;
   7.101 +
   7.102 +	for (i = 0; i < 10; i++) {
   7.103 +		/* They ack this in play_dead by setting CPU_DEAD */
   7.104 +		if (per_cpu(cpu_state, cpu) == CPU_DEAD)
   7.105 +			return;
   7.106 +		current->state = TASK_UNINTERRUPTIBLE;
   7.107 +		schedule_timeout(HZ/10);
   7.108 +	}
   7.109 + 	printk(KERN_ERR "CPU %u didn't die...\n", cpu);
   7.110 +}
   7.111 +#else /* ... !CONFIG_HOTPLUG_CPU */
   7.112 +int __cpu_disable(void)
   7.113 +{
   7.114 +	return -ENOSYS;
   7.115 +}
   7.116 +
   7.117 +void __cpu_die(unsigned int cpu)
   7.118 +{
   7.119 +	/* We said "no" in __cpu_disable */
   7.120 +	BUG();
   7.121 +}
   7.122 +#endif /* CONFIG_HOTPLUG_CPU */
   7.123 +
   7.124  int __devinit __cpu_up(unsigned int cpu)
   7.125  {
   7.126 -	/* This only works at boot for x86.  See "rewrite" above. */
   7.127 -	if (cpu_isset(cpu, smp_commenced_mask)) {
   7.128 -		local_irq_enable();
   7.129 -		return -ENOSYS;
   7.130 -	}
   7.131 -
   7.132  	/* In case one didn't come up */
   7.133  	if (!cpu_isset(cpu, cpu_callin_map)) {
   7.134 +		printk(KERN_DEBUG "skipping cpu%d, didn't come online\n", cpu);
   7.135  		local_irq_enable();
   7.136  		return -EIO;
   7.137  	}
   7.138  
   7.139 +#ifdef CONFIG_HOTPLUG_CPU
   7.140 +	/* Already up, and in cpu_quiescent now? */
   7.141 +	if (cpu_isset(cpu, smp_commenced_mask)) {
   7.142 +		cpu_enable(cpu);
   7.143 +		return 0;
   7.144 +	}
   7.145 +#endif
   7.146 +
   7.147  	local_irq_enable();
   7.148  	/* Unleash the CPU! */
   7.149  	cpu_set(cpu, smp_commenced_mask);
     8.1 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/traps.c	Tue May 03 14:27:54 2005 +0000
     8.2 +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/traps.c	Tue May 03 14:42:00 2005 +0000
     8.3 @@ -609,6 +609,14 @@ fastcall void do_nmi(struct pt_regs * re
     8.4  	nmi_enter();
     8.5  
     8.6  	cpu = smp_processor_id();
     8.7 +
     8.8 +#ifdef CONFIG_HOTPLUG_CPU
     8.9 +	if (!cpu_online(cpu)) {
    8.10 +		nmi_exit();
    8.11 +		return;
    8.12 +	}
    8.13 +#endif
    8.14 +
    8.15  	++nmi_count(cpu);
    8.16  
    8.17  	if (!nmi_callback(regs, cpu))
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/mach-default/Makefile	Tue May 03 14:42:00 2005 +0000
     9.3 @@ -0,0 +1,12 @@
     9.4 +#
     9.5 +# Makefile for the linux kernel.
     9.6 +#
     9.7 +
     9.8 +c-obj-y				:= topology.o
     9.9 +
    9.10 +$(patsubst %.o,$(obj)/%.c,$(c-obj-y)):
    9.11 +	@ln -fsn $(srctree)/arch/i386/mach-default/$(notdir $@) $@
    9.12 +
    9.13 +obj-y	+= $(c-obj-y)
    9.14 +
    9.15 +clean-files += $(patsubst %.o,%.c,$(c-obj-y) $(c-obj-))
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/patches/linux-2.6.11/i386-cpu-hotplug-updated-for-mm.patch	Tue May 03 14:42:00 2005 +0000
    10.3 @@ -0,0 +1,656 @@
    10.4 +
    10.5 +From: Zwane Mwaikambo <zwane@linuxpower.ca>
    10.6 +
    10.7 +Find attached the i386 cpu hotplug patch updated for Ingo's latest round of
    10.8 +goodies.  In order to avoid dumping cpu hotplug code into kernel/irq/* i
    10.9 +dropped the cpu_online check in do_IRQ() by modifying fixup_irqs().  The
   10.10 +difference being that on cpu offline, fixup_irqs() is called before we
   10.11 +clear the cpu from cpu_online_map and a long delay in order to ensure that
   10.12 +we never have any queued external interrupts on the APICs.  Due to my usual
   10.13 +test victims being in boxes a continent away this hasn't been tested, but
   10.14 +i'll cover bug reports (nudge, Nathan!  ;)
   10.15 +
   10.16 +1) Add CONFIG_HOTPLUG_CPU
   10.17 +2) disable local APIC timer on dead cpus.
   10.18 +3) Disable preempt around irq balancing to prevent CPUs going down.
   10.19 +4) Print irq stats for all possible cpus.
   10.20 +5) Debugging check for interrupts on offline cpus.
   10.21 +6) Hacky fixup_irqs() to redirect irqs when cpus go off/online.
   10.22 +7) play_dead() for offline cpus to spin inside.
   10.23 +8) Handle offline cpus set in flush_tlb_others().
   10.24 +9) Grab lock earlier in smp_call_function() to prevent CPUs going down.
   10.25 +10) Implement __cpu_disable() and __cpu_die().
   10.26 +11) Enable local interrupts in cpu_enable() after fixup_irqs()
   10.27 +12) Don't fiddle with NMI on dead cpu, but leave intact on other cpus.
   10.28 +13) Program IRQ affinity whilst cpu is still in cpu_online_map on offline.
   10.29 +
   10.30 +Signed-off-by: Zwane Mwaikambo <zwane@linuxpower.ca>
   10.31 +DESC
   10.32 +ppc64: fix hotplug cpu
   10.33 +EDESC
   10.34 +From: Zwane Mwaikambo <zwane@fsmlabs.com>
   10.35 +
   10.36 +I seem to have broken this when I moved the clearing of the dying cpu to 
   10.37 +arch specific code.
   10.38 +
   10.39 +Signed-off-by: Zwane Mwaikambo <zwane@fsmlabs.com>
   10.40 +Signed-off-by: Andrew Morton <akpm@osdl.org>
   10.41 +---
   10.42 +
   10.43 + 25-akpm/arch/i386/Kconfig               |    9 ++
   10.44 + 25-akpm/arch/i386/kernel/apic.c         |    3 
   10.45 + 25-akpm/arch/i386/kernel/io_apic.c      |    2 
   10.46 + 25-akpm/arch/i386/kernel/irq.c          |   66 +++++++++++++++++----
   10.47 + 25-akpm/arch/i386/kernel/msr.c          |    2 
   10.48 + 25-akpm/arch/i386/kernel/process.c      |   35 +++++++++++
   10.49 + 25-akpm/arch/i386/kernel/smp.c          |   25 +++++---
   10.50 + 25-akpm/arch/i386/kernel/smpboot.c      |   98 ++++++++++++++++++++++++++++++--
   10.51 + 25-akpm/arch/i386/kernel/traps.c        |    8 ++
   10.52 + 25-akpm/arch/ia64/kernel/smpboot.c      |    3 
   10.53 + 25-akpm/arch/ppc64/kernel/pSeries_smp.c |    5 +
   10.54 + 25-akpm/arch/s390/kernel/smp.c          |    4 -
   10.55 + 25-akpm/include/asm-i386/cpu.h          |    2 
   10.56 + 25-akpm/include/asm-i386/irq.h          |    4 +
   10.57 + 25-akpm/include/asm-i386/smp.h          |    3 
   10.58 + 25-akpm/kernel/cpu.c                    |   14 +---
   10.59 + arch/ppc64/kernel/smp.c                 |    0 
   10.60 + 17 files changed, 242 insertions(+), 41 deletions(-)
   10.61 +
   10.62 +diff -puN arch/i386/Kconfig~i386-cpu-hotplug-updated-for-mm arch/i386/Kconfig
   10.63 +--- 25/arch/i386/Kconfig~i386-cpu-hotplug-updated-for-mm	2005-02-23 02:20:06.000000000 -0800
   10.64 ++++ 25-akpm/arch/i386/Kconfig	2005-02-23 02:20:06.000000000 -0800
   10.65 +@@ -1205,6 +1205,15 @@ config SCx200
   10.66 + 	  This support is also available as a module.  If compiled as a
   10.67 + 	  module, it will be called scx200.
   10.68 + 
   10.69 ++config HOTPLUG_CPU
   10.70 ++	bool "Support for hot-pluggable CPUs (EXPERIMENTAL)"
   10.71 ++	depends on SMP && HOTPLUG && EXPERIMENTAL
   10.72 ++	---help---
   10.73 ++	  Say Y here to experiment with turning CPUs off and on.  CPUs
   10.74 ++	  can be controlled through /sys/devices/system/cpu.
   10.75 ++
   10.76 ++	  Say N.
   10.77 ++
   10.78 + source "drivers/pcmcia/Kconfig"
   10.79 + 
   10.80 + source "drivers/pci/hotplug/Kconfig"
   10.81 +diff -puN arch/i386/kernel/apic.c~i386-cpu-hotplug-updated-for-mm arch/i386/kernel/apic.c
   10.82 +--- 25/arch/i386/kernel/apic.c~i386-cpu-hotplug-updated-for-mm	2005-02-23 02:20:06.000000000 -0800
   10.83 ++++ 25-akpm/arch/i386/kernel/apic.c	2005-02-23 02:20:06.000000000 -0800
   10.84 +@@ -26,6 +26,7 @@
   10.85 + #include <linux/mc146818rtc.h>
   10.86 + #include <linux/kernel_stat.h>
   10.87 + #include <linux/sysdev.h>
   10.88 ++#include <linux/cpu.h>
   10.89 + 
   10.90 + #include <asm/atomic.h>
   10.91 + #include <asm/smp.h>
   10.92 +@@ -1048,7 +1049,7 @@ void __init setup_secondary_APIC_clock(v
   10.93 + 	setup_APIC_timer(calibration_result);
   10.94 + }
   10.95 + 
   10.96 +-void __init disable_APIC_timer(void)
   10.97 ++void __devinit disable_APIC_timer(void)
   10.98 + {
   10.99 + 	if (using_apic_timer) {
  10.100 + 		unsigned long v;
  10.101 +diff -puN arch/i386/kernel/io_apic.c~i386-cpu-hotplug-updated-for-mm arch/i386/kernel/io_apic.c
  10.102 +--- 25/arch/i386/kernel/io_apic.c~i386-cpu-hotplug-updated-for-mm	2005-02-23 02:20:06.000000000 -0800
  10.103 ++++ 25-akpm/arch/i386/kernel/io_apic.c	2005-02-23 02:20:06.000000000 -0800
  10.104 +@@ -576,9 +576,11 @@ static int balanced_irq(void *unused)
  10.105 + 		try_to_freeze(PF_FREEZE);
  10.106 + 		if (time_after(jiffies,
  10.107 + 				prev_balance_time+balanced_irq_interval)) {
  10.108 ++			preempt_disable();
  10.109 + 			do_irq_balance();
  10.110 + 			prev_balance_time = jiffies;
  10.111 + 			time_remaining = balanced_irq_interval;
  10.112 ++			preempt_enable();
  10.113 + 		}
  10.114 + 	}
  10.115 + 	return 0;
  10.116 +diff -puN arch/i386/kernel/irq.c~i386-cpu-hotplug-updated-for-mm arch/i386/kernel/irq.c
  10.117 +--- 25/arch/i386/kernel/irq.c~i386-cpu-hotplug-updated-for-mm	2005-02-23 02:20:06.000000000 -0800
  10.118 ++++ 25-akpm/arch/i386/kernel/irq.c	2005-02-23 02:20:06.000000000 -0800
  10.119 +@@ -15,6 +15,9 @@
  10.120 + #include <linux/seq_file.h>
  10.121 + #include <linux/interrupt.h>
  10.122 + #include <linux/kernel_stat.h>
  10.123 ++#include <linux/notifier.h>
  10.124 ++#include <linux/cpu.h>
  10.125 ++#include <linux/delay.h>
  10.126 + 
  10.127 + #ifndef CONFIG_X86_LOCAL_APIC
  10.128 + /*
  10.129 +@@ -209,9 +212,8 @@ int show_interrupts(struct seq_file *p, 
  10.130 + 
  10.131 + 	if (i == 0) {
  10.132 + 		seq_printf(p, "           ");
  10.133 +-		for (j=0; j<NR_CPUS; j++)
  10.134 +-			if (cpu_online(j))
  10.135 +-				seq_printf(p, "CPU%d       ",j);
  10.136 ++		for_each_cpu(j)
  10.137 ++			seq_printf(p, "CPU%d       ",j);
  10.138 + 		seq_putc(p, '\n');
  10.139 + 	}
  10.140 + 
  10.141 +@@ -224,9 +226,8 @@ int show_interrupts(struct seq_file *p, 
  10.142 + #ifndef CONFIG_SMP
  10.143 + 		seq_printf(p, "%10u ", kstat_irqs(i));
  10.144 + #else
  10.145 +-		for (j = 0; j < NR_CPUS; j++)
  10.146 +-			if (cpu_online(j))
  10.147 +-				seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
  10.148 ++		for_each_cpu(j)
  10.149 ++			seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
  10.150 + #endif
  10.151 + 		seq_printf(p, " %14s", irq_desc[i].handler->typename);
  10.152 + 		seq_printf(p, "  %s", action->name);
  10.153 +@@ -239,16 +240,13 @@ skip:
  10.154 + 		spin_unlock_irqrestore(&irq_desc[i].lock, flags);
  10.155 + 	} else if (i == NR_IRQS) {
  10.156 + 		seq_printf(p, "NMI: ");
  10.157 +-		for (j = 0; j < NR_CPUS; j++)
  10.158 +-			if (cpu_online(j))
  10.159 +-				seq_printf(p, "%10u ", nmi_count(j));
  10.160 ++		for_each_cpu(j)
  10.161 ++			seq_printf(p, "%10u ", nmi_count(j));
  10.162 + 		seq_putc(p, '\n');
  10.163 + #ifdef CONFIG_X86_LOCAL_APIC
  10.164 + 		seq_printf(p, "LOC: ");
  10.165 +-		for (j = 0; j < NR_CPUS; j++)
  10.166 +-			if (cpu_online(j))
  10.167 +-				seq_printf(p, "%10u ",
  10.168 +-					irq_stat[j].apic_timer_irqs);
  10.169 ++		for_each_cpu(j)
  10.170 ++			seq_printf(p, "%10u ", irq_stat[j].apic_timer_irqs);
  10.171 + 		seq_putc(p, '\n');
  10.172 + #endif
  10.173 + 		seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
  10.174 +@@ -258,3 +256,45 @@ skip:
  10.175 + 	}
  10.176 + 	return 0;
  10.177 + }
  10.178 ++
  10.179 ++#ifdef CONFIG_HOTPLUG_CPU
  10.180 ++#include <mach_apic.h>
  10.181 ++
  10.182 ++void fixup_irqs(cpumask_t map)
  10.183 ++{
  10.184 ++	unsigned int irq;
  10.185 ++	static int warned;
  10.186 ++
  10.187 ++	for (irq = 0; irq < NR_IRQS; irq++) {
  10.188 ++		cpumask_t mask;
  10.189 ++		if (irq == 2)
  10.190 ++			continue;
  10.191 ++
  10.192 ++		cpus_and(mask, irq_affinity[irq], map);
  10.193 ++		if (any_online_cpu(mask) == NR_CPUS) {
  10.194 ++			printk("Breaking affinity for irq %i\n", irq);
  10.195 ++			mask = map;
  10.196 ++		}
  10.197 ++		if (irq_desc[irq].handler->set_affinity)
  10.198 ++			irq_desc[irq].handler->set_affinity(irq, mask);
  10.199 ++		else if (irq_desc[irq].action && !(warned++))
  10.200 ++			printk("Cannot set affinity for irq %i\n", irq);
  10.201 ++	}
  10.202 ++
  10.203 ++#if 0
  10.204 ++	barrier();
  10.205 ++	/* Ingo Molnar says: "after the IO-APIC masks have been redirected
  10.206 ++	   [note the nop - the interrupt-enable boundary on x86 is two
  10.207 ++	   instructions from sti] - to flush out pending hardirqs and
  10.208 ++	   IPIs. After this point nothing is supposed to reach this CPU." */
  10.209 ++	__asm__ __volatile__("sti; nop; cli");
  10.210 ++	barrier();
  10.211 ++#else
  10.212 ++	/* That doesn't seem sufficient.  Give it 1ms. */
  10.213 ++	local_irq_enable();
  10.214 ++	mdelay(1);
  10.215 ++	local_irq_disable();
  10.216 ++#endif
  10.217 ++}
  10.218 ++#endif
  10.219 ++
  10.220 +diff -puN arch/i386/kernel/msr.c~i386-cpu-hotplug-updated-for-mm arch/i386/kernel/msr.c
  10.221 +--- 25/arch/i386/kernel/msr.c~i386-cpu-hotplug-updated-for-mm	2005-02-23 02:20:06.000000000 -0800
  10.222 ++++ 25-akpm/arch/i386/kernel/msr.c	2005-02-23 02:20:06.000000000 -0800
  10.223 +@@ -260,7 +260,7 @@ static struct file_operations msr_fops =
  10.224 + 	.open = msr_open,
  10.225 + };
  10.226 + 
  10.227 +-static int msr_class_simple_device_add(int i)
  10.228 ++static int __devinit msr_class_simple_device_add(int i)
  10.229 + {
  10.230 + 	int err = 0;
  10.231 + 	struct class_device *class_err;
  10.232 +diff -puN arch/i386/kernel/process.c~i386-cpu-hotplug-updated-for-mm arch/i386/kernel/process.c
  10.233 +--- 25/arch/i386/kernel/process.c~i386-cpu-hotplug-updated-for-mm	2005-02-23 02:20:06.000000000 -0800
  10.234 ++++ 25-akpm/arch/i386/kernel/process.c	2005-02-23 02:20:06.000000000 -0800
  10.235 +@@ -13,6 +13,7 @@
  10.236 + 
  10.237 + #include <stdarg.h>
  10.238 + 
  10.239 ++#include <linux/cpu.h>
  10.240 + #include <linux/errno.h>
  10.241 + #include <linux/sched.h>
  10.242 + #include <linux/fs.h>
  10.243 +@@ -55,6 +56,9 @@
  10.244 + #include <linux/irq.h>
  10.245 + #include <linux/err.h>
  10.246 + 
  10.247 ++#include <asm/tlbflush.h>
  10.248 ++#include <asm/cpu.h>
  10.249 ++
  10.250 + asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
  10.251 + 
  10.252 + int hlt_counter;
  10.253 +@@ -139,6 +143,34 @@ static void poll_idle (void)
  10.254 + 	}
  10.255 + }
  10.256 + 
  10.257 ++#ifdef CONFIG_HOTPLUG_CPU
  10.258 ++#include <asm/nmi.h>
  10.259 ++/* We don't actually take CPU down, just spin without interrupts. */
  10.260 ++static inline void play_dead(void)
  10.261 ++{
  10.262 ++	/* Ack it */
  10.263 ++	__get_cpu_var(cpu_state) = CPU_DEAD;
  10.264 ++
  10.265 ++	/* We shouldn't have to disable interrupts while dead, but
  10.266 ++	 * some interrupts just don't seem to go away, and this makes
  10.267 ++	 * it "work" for testing purposes. */
  10.268 ++	/* Death loop */
  10.269 ++	while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE)
  10.270 ++		cpu_relax();
  10.271 ++
  10.272 ++	local_irq_disable();
  10.273 ++	__flush_tlb_all();
  10.274 ++	cpu_set(smp_processor_id(), cpu_online_map);
  10.275 ++	enable_APIC_timer();
  10.276 ++	local_irq_enable();
  10.277 ++}
  10.278 ++#else
  10.279 ++static inline void play_dead(void)
  10.280 ++{
  10.281 ++	BUG();
  10.282 ++}
  10.283 ++#endif /* CONFIG_HOTPLUG_CPU */
  10.284 ++
  10.285 + /*
  10.286 +  * The idle thread. There's no useful work to be
  10.287 +  * done, so just try to conserve power and have a
  10.288 +@@ -162,6 +194,9 @@ void cpu_idle (void)
  10.289 + 			if (!idle)
  10.290 + 				idle = default_idle;
  10.291 + 
  10.292 ++			if (cpu_is_offline(cpu))
  10.293 ++				play_dead();
  10.294 ++
  10.295 + 			irq_stat[cpu].idle_timestamp = jiffies;
  10.296 + 			idle();
  10.297 + 		}
  10.298 +diff -puN arch/i386/kernel/smpboot.c~i386-cpu-hotplug-updated-for-mm arch/i386/kernel/smpboot.c
  10.299 +--- 25/arch/i386/kernel/smpboot.c~i386-cpu-hotplug-updated-for-mm	2005-02-23 02:20:06.000000000 -0800
  10.300 ++++ 25-akpm/arch/i386/kernel/smpboot.c	2005-02-23 02:20:06.000000000 -0800
  10.301 +@@ -44,6 +44,9 @@
  10.302 + #include <linux/smp_lock.h>
  10.303 + #include <linux/irq.h>
  10.304 + #include <linux/bootmem.h>
  10.305 ++#include <linux/notifier.h>
  10.306 ++#include <linux/cpu.h>
  10.307 ++#include <linux/percpu.h>
  10.308 + 
  10.309 + #include <linux/delay.h>
  10.310 + #include <linux/mc146818rtc.h>
  10.311 +@@ -89,6 +92,9 @@ extern unsigned char trampoline_end  [];
  10.312 + static unsigned char *trampoline_base;
  10.313 + static int trampoline_exec;
  10.314 + 
  10.315 ++/* State of each CPU. */
  10.316 ++DEFINE_PER_CPU(int, cpu_state) = { 0 };
  10.317 ++
  10.318 + /*
  10.319 +  * Currently trivial. Write the real->protected mode
  10.320 +  * bootstrap into the page concerned. The caller
  10.321 +@@ -1095,6 +1101,9 @@ static void __init smp_boot_cpus(unsigne
  10.322 +    who understands all this stuff should rewrite it properly. --RR 15/Jul/02 */
  10.323 + void __init smp_prepare_cpus(unsigned int max_cpus)
  10.324 + {
  10.325 ++	smp_commenced_mask = cpumask_of_cpu(0);
  10.326 ++	cpu_callin_map = cpumask_of_cpu(0);
  10.327 ++	mb();
  10.328 + 	smp_boot_cpus(max_cpus);
  10.329 + }
  10.330 + 
  10.331 +@@ -1104,20 +1113,99 @@ void __devinit smp_prepare_boot_cpu(void
  10.332 + 	cpu_set(smp_processor_id(), cpu_callout_map);
  10.333 + }
  10.334 + 
  10.335 +-int __devinit __cpu_up(unsigned int cpu)
  10.336 ++#ifdef CONFIG_HOTPLUG_CPU
  10.337 ++
  10.338 ++/* must be called with the cpucontrol mutex held */
  10.339 ++static int __devinit cpu_enable(unsigned int cpu)
  10.340 + {
  10.341 +-	/* This only works at boot for x86.  See "rewrite" above. */
  10.342 +-	if (cpu_isset(cpu, smp_commenced_mask)) {
  10.343 +-		local_irq_enable();
  10.344 +-		return -ENOSYS;
  10.345 ++	/* get the target out of its holding state */
  10.346 ++	per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
  10.347 ++	wmb();
  10.348 ++
  10.349 ++	/* wait for the processor to ack it. timeout? */
  10.350 ++	while (!cpu_online(cpu))
  10.351 ++		cpu_relax();
  10.352 ++
  10.353 ++	fixup_irqs(cpu_online_map);
  10.354 ++	/* counter the disable in fixup_irqs() */
  10.355 ++	local_irq_enable();
  10.356 ++	return 0;
  10.357 ++}
  10.358 ++
  10.359 ++int __cpu_disable(void)
  10.360 ++{
  10.361 ++	cpumask_t map = cpu_online_map;
  10.362 ++	int cpu = smp_processor_id();
  10.363 ++
  10.364 ++	/*
  10.365 ++	 * Perhaps use cpufreq to drop frequency, but that could go
  10.366 ++	 * into generic code.
  10.367 ++ 	 *
  10.368 ++	 * We won't take down the boot processor on i386 due to some
  10.369 ++	 * interrupts only being able to be serviced by the BSP.
  10.370 ++	 * Especially so if we're not using an IOAPIC	-zwane
  10.371 ++	 */
  10.372 ++	if (cpu == 0)
  10.373 ++		return -EBUSY;
  10.374 ++
  10.375 ++	/* We enable the timer again on the exit path of the death loop */
  10.376 ++	disable_APIC_timer();
  10.377 ++	/* Allow any queued timer interrupts to get serviced */
  10.378 ++	local_irq_enable();
  10.379 ++	mdelay(1);
  10.380 ++	local_irq_disable();
  10.381 ++
  10.382 ++	cpu_clear(cpu, map);
  10.383 ++	fixup_irqs(map);
  10.384 ++	/* It's now safe to remove this processor from the online map */
  10.385 ++	cpu_clear(cpu, cpu_online_map);
  10.386 ++	return 0;
  10.387 ++}
  10.388 ++
  10.389 ++void __cpu_die(unsigned int cpu)
  10.390 ++{
  10.391 ++	/* We don't do anything here: idle task is faking death itself. */
  10.392 ++	unsigned int i;
  10.393 ++
  10.394 ++	for (i = 0; i < 10; i++) {
  10.395 ++		/* They ack this in play_dead by setting CPU_DEAD */
  10.396 ++		if (per_cpu(cpu_state, cpu) == CPU_DEAD)
  10.397 ++			return;
  10.398 ++		current->state = TASK_UNINTERRUPTIBLE;
  10.399 ++		schedule_timeout(HZ/10);
  10.400 + 	}
  10.401 ++ 	printk(KERN_ERR "CPU %u didn't die...\n", cpu);
  10.402 ++}
  10.403 ++#else /* ... !CONFIG_HOTPLUG_CPU */
  10.404 ++int __cpu_disable(void)
  10.405 ++{
  10.406 ++	return -ENOSYS;
  10.407 ++}
  10.408 + 
  10.409 ++void __cpu_die(unsigned int cpu)
  10.410 ++{
  10.411 ++	/* We said "no" in __cpu_disable */
  10.412 ++	BUG();
  10.413 ++}
  10.414 ++#endif /* CONFIG_HOTPLUG_CPU */
  10.415 ++
  10.416 ++int __devinit __cpu_up(unsigned int cpu)
  10.417 ++{
  10.418 + 	/* In case one didn't come up */
  10.419 + 	if (!cpu_isset(cpu, cpu_callin_map)) {
  10.420 ++		printk(KERN_DEBUG "skipping cpu%d, didn't come online\n", cpu);
  10.421 + 		local_irq_enable();
  10.422 + 		return -EIO;
  10.423 + 	}
  10.424 + 
  10.425 ++#ifdef CONFIG_HOTPLUG_CPU
  10.426 ++	/* Already up, and in cpu_quiescent now? */
  10.427 ++	if (cpu_isset(cpu, smp_commenced_mask)) {
  10.428 ++		cpu_enable(cpu);
  10.429 ++		return 0;
  10.430 ++	}
  10.431 ++#endif
  10.432 ++
  10.433 + 	local_irq_enable();
  10.434 + 	/* Unleash the CPU! */
  10.435 + 	cpu_set(cpu, smp_commenced_mask);
  10.436 +diff -puN arch/i386/kernel/smp.c~i386-cpu-hotplug-updated-for-mm arch/i386/kernel/smp.c
  10.437 +--- 25/arch/i386/kernel/smp.c~i386-cpu-hotplug-updated-for-mm	2005-02-23 02:20:06.000000000 -0800
  10.438 ++++ 25-akpm/arch/i386/kernel/smp.c	2005-02-23 02:20:06.000000000 -0800
  10.439 +@@ -19,6 +19,7 @@
  10.440 + #include <linux/mc146818rtc.h>
  10.441 + #include <linux/cache.h>
  10.442 + #include <linux/interrupt.h>
  10.443 ++#include <linux/cpu.h>
  10.444 + 
  10.445 + #include <asm/mtrr.h>
  10.446 + #include <asm/tlbflush.h>
  10.447 +@@ -163,7 +164,7 @@ void send_IPI_mask_bitmask(cpumask_t cpu
  10.448 + 	unsigned long flags;
  10.449 + 
  10.450 + 	local_irq_save(flags);
  10.451 +-		
  10.452 ++	WARN_ON(mask & ~cpus_addr(cpu_online_map)[0]);
  10.453 + 	/*
  10.454 + 	 * Wait for idle.
  10.455 + 	 */
  10.456 +@@ -345,21 +346,21 @@ out:
  10.457 + static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
  10.458 + 						unsigned long va)
  10.459 + {
  10.460 +-	cpumask_t tmp;
  10.461 + 	/*
  10.462 + 	 * A couple of (to be removed) sanity checks:
  10.463 + 	 *
  10.464 +-	 * - we do not send IPIs to not-yet booted CPUs.
  10.465 + 	 * - current CPU must not be in mask
  10.466 + 	 * - mask must exist :)
  10.467 + 	 */
  10.468 + 	BUG_ON(cpus_empty(cpumask));
  10.469 +-
  10.470 +-	cpus_and(tmp, cpumask, cpu_online_map);
  10.471 +-	BUG_ON(!cpus_equal(cpumask, tmp));
  10.472 + 	BUG_ON(cpu_isset(smp_processor_id(), cpumask));
  10.473 + 	BUG_ON(!mm);
  10.474 + 
  10.475 ++	/* If a CPU which we ran on has gone down, OK. */
  10.476 ++	cpus_and(cpumask, cpumask, cpu_online_map);
  10.477 ++	if (cpus_empty(cpumask))
  10.478 ++		return;
  10.479 ++
  10.480 + 	/*
  10.481 + 	 * i'm not happy about this global shared spinlock in the
  10.482 + 	 * MM hot path, but we'll see how contended it is.
  10.483 +@@ -484,6 +485,7 @@ void smp_send_nmi_allbutself(void)
  10.484 +  */
  10.485 + void smp_send_reschedule(int cpu)
  10.486 + {
  10.487 ++	WARN_ON(cpu_is_offline(cpu));
  10.488 + 	send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR);
  10.489 + }
  10.490 + 
  10.491 +@@ -524,10 +526,16 @@ int smp_call_function (void (*func) (voi
  10.492 +  */
  10.493 + {
  10.494 + 	struct call_data_struct data;
  10.495 +-	int cpus = num_online_cpus()-1;
  10.496 ++	int cpus;
  10.497 + 
  10.498 +-	if (!cpus)
  10.499 ++	/* Holding any lock stops cpus from going down. */
  10.500 ++	spin_lock(&call_lock);
  10.501 ++	cpus = num_online_cpus()-1;
  10.502 ++
  10.503 ++	if (!cpus) {
  10.504 ++		spin_unlock(&call_lock);
  10.505 + 		return 0;
  10.506 ++	}
  10.507 + 
  10.508 + 	/* Can deadlock when called with interrupts disabled */
  10.509 + 	WARN_ON(irqs_disabled());
  10.510 +@@ -539,7 +547,6 @@ int smp_call_function (void (*func) (voi
  10.511 + 	if (wait)
  10.512 + 		atomic_set(&data.finished, 0);
  10.513 + 
  10.514 +-	spin_lock(&call_lock);
  10.515 + 	call_data = &data;
  10.516 + 	mb();
  10.517 + 	
  10.518 +diff -puN arch/i386/kernel/traps.c~i386-cpu-hotplug-updated-for-mm arch/i386/kernel/traps.c
  10.519 +--- 25/arch/i386/kernel/traps.c~i386-cpu-hotplug-updated-for-mm	2005-02-23 02:20:06.000000000 -0800
  10.520 ++++ 25-akpm/arch/i386/kernel/traps.c	2005-02-23 02:20:06.000000000 -0800
  10.521 +@@ -669,6 +669,14 @@ fastcall void do_nmi(struct pt_regs * re
  10.522 + 	nmi_enter();
  10.523 + 
  10.524 + 	cpu = smp_processor_id();
  10.525 ++
  10.526 ++#ifdef CONFIG_HOTPLUG_CPU
  10.527 ++	if (!cpu_online(cpu)) {
  10.528 ++		nmi_exit();
  10.529 ++		return;
  10.530 ++	}
  10.531 ++#endif
  10.532 ++
  10.533 + 	++nmi_count(cpu);
  10.534 + 
  10.535 + 	if (!nmi_callback(regs, cpu))
  10.536 +diff -puN arch/ia64/kernel/smpboot.c~i386-cpu-hotplug-updated-for-mm arch/ia64/kernel/smpboot.c
  10.537 +--- 25/arch/ia64/kernel/smpboot.c~i386-cpu-hotplug-updated-for-mm	2005-02-23 02:20:06.000000000 -0800
  10.538 ++++ 25-akpm/arch/ia64/kernel/smpboot.c	2005-02-23 02:20:06.000000000 -0800
  10.539 +@@ -590,9 +590,10 @@ int __cpu_disable(void)
  10.540 + 	if (cpu == 0)
  10.541 + 		return -EBUSY;
  10.542 + 
  10.543 ++	cpu_clear(cpu, cpu_online_map);
  10.544 + 	fixup_irqs();
  10.545 + 	local_flush_tlb_all();
  10.546 +-	printk ("Disabled cpu %u\n", smp_processor_id());
  10.547 ++	printk("Disabled cpu %u\n", cpu);
  10.548 + 	return 0;
  10.549 + }
  10.550 + 
  10.551 +diff -puN arch/ppc64/kernel/smp.c~i386-cpu-hotplug-updated-for-mm arch/ppc64/kernel/smp.c
  10.552 +diff -puN arch/s390/kernel/smp.c~i386-cpu-hotplug-updated-for-mm arch/s390/kernel/smp.c
  10.553 +--- 25/arch/s390/kernel/smp.c~i386-cpu-hotplug-updated-for-mm	2005-02-23 02:20:06.000000000 -0800
  10.554 ++++ 25-akpm/arch/s390/kernel/smp.c	2005-02-23 02:20:06.000000000 -0800
  10.555 +@@ -679,12 +679,14 @@ __cpu_disable(void)
  10.556 + {
  10.557 + 	unsigned long flags;
  10.558 + 	ec_creg_mask_parms cr_parms;
  10.559 ++	int cpu = smp_processor_id();
  10.560 + 
  10.561 + 	spin_lock_irqsave(&smp_reserve_lock, flags);
  10.562 +-	if (smp_cpu_reserved[smp_processor_id()] != 0) {
  10.563 ++	if (smp_cpu_reserved[cpu] != 0) {
  10.564 + 		spin_unlock_irqrestore(&smp_reserve_lock, flags);
  10.565 + 		return -EBUSY;
  10.566 + 	}
  10.567 ++	cpu_clear(cpu, cpu_online_map);
  10.568 + 
  10.569 + #ifdef CONFIG_PFAULT
  10.570 + 	/* Disable pfault pseudo page faults on this cpu. */
  10.571 +diff -puN include/asm-i386/cpu.h~i386-cpu-hotplug-updated-for-mm include/asm-i386/cpu.h
  10.572 +--- 25/include/asm-i386/cpu.h~i386-cpu-hotplug-updated-for-mm	2005-02-23 02:20:06.000000000 -0800
  10.573 ++++ 25-akpm/include/asm-i386/cpu.h	2005-02-23 02:20:06.000000000 -0800
  10.574 +@@ -5,6 +5,7 @@
  10.575 + #include <linux/cpu.h>
  10.576 + #include <linux/topology.h>
  10.577 + #include <linux/nodemask.h>
  10.578 ++#include <linux/percpu.h>
  10.579 + 
  10.580 + #include <asm/node.h>
  10.581 + 
  10.582 +@@ -17,4 +18,5 @@ extern int arch_register_cpu(int num);
  10.583 + extern void arch_unregister_cpu(int);
  10.584 + #endif
  10.585 + 
  10.586 ++DECLARE_PER_CPU(int, cpu_state);
  10.587 + #endif /* _ASM_I386_CPU_H_ */
  10.588 +diff -puN include/asm-i386/irq.h~i386-cpu-hotplug-updated-for-mm include/asm-i386/irq.h
  10.589 +--- 25/include/asm-i386/irq.h~i386-cpu-hotplug-updated-for-mm	2005-02-23 02:20:06.000000000 -0800
  10.590 ++++ 25-akpm/include/asm-i386/irq.h	2005-02-23 02:20:06.000000000 -0800
  10.591 +@@ -38,4 +38,8 @@ extern void release_vm86_irqs(struct tas
  10.592 + extern int irqbalance_disable(char *str);
  10.593 + #endif
  10.594 + 
  10.595 ++#ifdef CONFIG_HOTPLUG_CPU
  10.596 ++extern void fixup_irqs(cpumask_t map);
  10.597 ++#endif
  10.598 ++
  10.599 + #endif /* _ASM_IRQ_H */
  10.600 +diff -puN include/asm-i386/smp.h~i386-cpu-hotplug-updated-for-mm include/asm-i386/smp.h
  10.601 +--- 25/include/asm-i386/smp.h~i386-cpu-hotplug-updated-for-mm	2005-02-23 02:20:06.000000000 -0800
  10.602 ++++ 25-akpm/include/asm-i386/smp.h	2005-02-23 02:20:06.000000000 -0800
  10.603 +@@ -85,6 +85,9 @@ static __inline int logical_smp_processo
  10.604 + }
  10.605 + 
  10.606 + #endif
  10.607 ++
  10.608 ++extern int __cpu_disable(void);
  10.609 ++extern void __cpu_die(unsigned int cpu);
  10.610 + #endif /* !__ASSEMBLY__ */
  10.611 + 
  10.612 + #define NO_PROC_ID		0xFF		/* No processor magic marker */
  10.613 +diff -puN kernel/cpu.c~i386-cpu-hotplug-updated-for-mm kernel/cpu.c
  10.614 +--- 25/kernel/cpu.c~i386-cpu-hotplug-updated-for-mm	2005-02-23 02:20:06.000000000 -0800
  10.615 ++++ 25-akpm/kernel/cpu.c	2005-02-23 02:20:06.000000000 -0800
  10.616 +@@ -63,19 +63,15 @@ static int take_cpu_down(void *unused)
  10.617 + {
  10.618 + 	int err;
  10.619 + 
  10.620 +-	/* Take offline: makes arch_cpu_down somewhat easier. */
  10.621 +-	cpu_clear(smp_processor_id(), cpu_online_map);
  10.622 +-
  10.623 + 	/* Ensure this CPU doesn't handle any more interrupts. */
  10.624 + 	err = __cpu_disable();
  10.625 + 	if (err < 0)
  10.626 +-		cpu_set(smp_processor_id(), cpu_online_map);
  10.627 +-	else
  10.628 +-		/* Force idle task to run as soon as we yield: it should
  10.629 +-		   immediately notice cpu is offline and die quickly. */
  10.630 +-		sched_idle_next();
  10.631 ++		return err;
  10.632 + 
  10.633 +-	return err;
  10.634 ++	/* Force idle task to run as soon as we yield: it should
  10.635 ++	   immediately notice cpu is offline and die quickly. */
  10.636 ++	sched_idle_next();
  10.637 ++	return 0;
  10.638 + }
  10.639 + 
  10.640 + int cpu_down(unsigned int cpu)
  10.641 +diff -puN arch/ppc64/kernel/pSeries_smp.c~i386-cpu-hotplug-updated-for-mm arch/ppc64/kernel/pSeries_smp.c
  10.642 +--- 25/arch/ppc64/kernel/pSeries_smp.c~i386-cpu-hotplug-updated-for-mm	2005-02-23 02:20:08.000000000 -0800
  10.643 ++++ 25-akpm/arch/ppc64/kernel/pSeries_smp.c	2005-02-23 02:20:08.000000000 -0800
  10.644 +@@ -86,10 +86,13 @@ static int query_cpu_stopped(unsigned in
  10.645 + 
  10.646 + int pSeries_cpu_disable(void)
  10.647 + {
  10.648 ++	int cpu = smp_processor_id();
  10.649 ++
  10.650 ++	cpu_clear(cpu, cpu_online_map);
  10.651 + 	systemcfg->processorCount--;
  10.652 + 
  10.653 + 	/*fix boot_cpuid here*/
  10.654 +-	if (smp_processor_id() == boot_cpuid)
  10.655 ++	if (cpu == boot_cpuid)
  10.656 + 		boot_cpuid = any_online_cpu(cpu_online_map);
  10.657 + 
  10.658 + 	/* FIXME: abstract this to not be platform specific later on */
  10.659 +_